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_Authorizationcookie orCf-Access-Jwt-Assertionheader (Cloudflare-mode deployments), or - a local JWT in the
Authorization: Bearer <token>header (local-mode deployments — obtained viaPOST /api/v1/auth/login), or - an API key in the
Authorization: Bearer sk-<key>header for machine-to-machine callers.
Base URL¶
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¶
Response:
{
"items": [
{
"id": "uuid",
"name": "SOC 2 Type II",
"version": "2017",
"description": "Trust Services Criteria",
"control_count": 61
}
]
}
Get Framework¶
List Framework Controls¶
Organizations¶
List Organizations¶
Create Organization¶
Get Organization¶
Update Organization¶
Delete Organization¶
Users¶
Get Current User¶
List Organization 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¶
Update User¶
Delete User¶
Deactivate / Invite¶
Assessments¶
List 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¶
Delete Assessment¶
Execute Assessment¶
Start AI-powered assessment execution.
Resume Assessment¶
Resume a paused assessment.
Cancel Assessment¶
Get Assessment Status¶
Response:
{
"status": "in_progress",
"progress": 45,
"controls_evaluated": 29,
"controls_total": 64,
"current_control": "CC6.1"
}
Findings¶
List 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¶
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¶
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¶
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¶
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¶
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):
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:
See the A2A CLI for a concrete client: python -m src.backend.a2a.cli attest ….
Incidents¶
List 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¶
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¶
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.
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.
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¶
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¶
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:
Get Download URL¶
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¶
Bulk Import¶
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¶
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:
Interactive API documentation (Swagger UI):