Skip to content

API Reference

Sovereign GRC exposes a REST API at /api/v1/. As of v2.0.5 the backend ships 400+ 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
/openapi.json Machine-readable OpenAPI 3.1 schema (always available)
/docs Interactive Swagger UI — development only
/redoc ReDoc-rendered reference — development only

The interactive /docs and /redoc UIs are enabled only when ENVIRONMENT=development; they are disabled in production. The /openapi.json schema is always served. In development they live at http://localhost:8000/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:

{
  "frameworks": [
    {
      "id": "SOC2",
      "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",
  "slug": "acme-corp"
}

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",
  "display_name": "John Doe",
  "role": "auditor"
}

Roles: admin, manager, compliance_manager, auditor, 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 - Filter by framework - status - Filter by status (pending, running, completed, failed)

Create Assessment

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

{
  "framework": "SOC2",
  "name": "Q1 2026 SOC 2 Assessment",
  "version": "2017"
}

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:

{
  "assessment_id": "uuid",
  "status": "running",
  "progress": 45,
  "current_node": "evaluate_controls",
  "next_nodes": ["aggregate_findings"],
  "is_interrupted": false
}


Findings

List Findings

GET /orgs/{org_id}/findings

Query Parameters: - assessment_id - Filter by assessment - status - Filter by status (pass, fail, not_applicable, manual_review) - 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": "Implemented MFA for all users"
}

Risk Management

The risk surface was restructured in v2.0 into 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:

{
  "scenario_id": "uuid",
  "owner_id": "uuid",
  "business_unit": "Engineering",
  "inherent_likelihood": 3,
  "inherent_impact": 4,
  "residual_likelihood": 2,
  "residual_impact": 3,
  "treatment_strategy": "mitigate",
  "treatment_plan": "Roll out vendor security reviews and contractual controls"
}

A register entry instantiates a RiskScenario (referenced by scenario_id), so create the scenario under /risks/scenarios first.

Likelihood/Impact Scale: 1–5 (1 = Very Low, 5 = Very High) Treatment Strategy: mitigate, accept, transfer, avoid Risk Appetite Status: within_appetite, approaching_limit, exceeds_appetite, critical

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:

{
  "risks": [
    {
      "id": "uuid",
      "title": "Ransomware Attack",
      "inherent_likelihood": 3,
      "inherent_impact": 4,
      "inherent_score": 12,
      "residual_likelihood": 2,
      "residual_impact": 3,
      "residual_score": 6,
      "appetite_status": "within_appetite",
      "treatment": "mitigate"
    }
  ],
  "summary": {}
}

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

{
  "current_value": 245
}

Vendors

List Vendors

GET /orgs/{org_id}/vendors

Query Parameters: - status - Filter by status (prospective, onboarding, active, under_review, watch_list, offboarding, terminated) - tier - Filter by criticality tier (strategic, critical, operational, commodity)

Create Vendor

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

{
  "name": "Cloud Provider Inc",
  "service_categories": ["infrastructure"],
  "criticality_tier": "critical",
  "primary_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",
  "inherent_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 is a JSON-RPC 2.0 request; the compliance/attest method requests an attestation for a single framework, with an optional list of controls (omit for all) and a requesting_party:

{
  "jsonrpc": "2.0",
  "method": "compliance/attest",
  "params": {
    "framework": "SOC2",
    "controls": ["CC6.1", "CC6.2"],
    "requesting_party": {
      "name": "ACME Corp",
      "identifier": "DUNS:123456789"
    },
    "nonce": "..."
  },
  "id": "request-123"
}

The other supported methods are compliance/verify, compliance/status, and compliance/capabilities.

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 (new, triaging, in_progress, pending, resolved, closed, false_positive) - severity - Filter by severity (critical, high, medium, low, informational) - 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"]
}

Categories: malicious_code, unauthorized_access, data_breach, denial_of_service, phishing, insider_threat, physical_security, 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/orgs/{org_id}/opa/test with the incident context to evaluate a ransomware / phishing / DoS playbook policy. See the OpenAPI schema 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,
  "process_owner_id": "uuid"
}

Criticality: mission_critical, business_critical, important, support

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",
  "assessment_id": "uuid",
  "control_id": "CC6.1"
}

Response:

{
  "upload_url": "https://...",
  "object_key": "evidence/...",
  "expires_in": 3600,
  "max_size": 104857600
}

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

{
  "report_type": "detailed_findings",
  "assessment_id": "uuid",
  "format": "pdf"
}

Report Types: executive_summary, detailed_findings, remediation_plan, evidence_package, gap_analysis, statement_of_applicability, system_security_plan, poam

Formats: pdf, json, csv, html, xlsx

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",
  "components": {
    "database": "healthy",
    "redis": "healthy",
    "llm": "healthy"
  },
  "version": "2.0.0",
  "timestamp": "2026-06-20T15:48:22+00:00",
  "uptime_seconds": 56876.63
}


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.1 specification is available at:

GET /openapi.json

Interactive API documentation (Swagger UI) — available only when ENVIRONMENT=development, disabled in production:

GET /docs