Skip to main content

CloudForge API Reference

Base URL: /api/v1 (all endpoints require JWT authentication unless noted)

Auth note:

  • The API accepts bearer JWTs issued by the demo/static auth path or an external IdP.
  • Frontend Okta login is handled in the SPA; the API does not expose backend /authorize or /callback routes.

Pagination Contract

List endpoints accept query parameters:

  • page (default: 1) — 1-indexed page number
  • per_page (default: 50, max: 200) — items per page

Response envelope:

{
"data": [...],
"page": 1,
"per_page": 50,
"total": 247,
"total_pages": 5
}

Error Response Format

All errors return:

{
"code": "FINDING_NOT_FOUND",
"message": "finding not found",
"status": 404
}

Error codes: BAD_REQUEST, FORBIDDEN, NOT_FOUND, {RESOURCE}_NOT_FOUND, CONFLICT, RATE_LIMITED, SERVICE_UNAVAILABLE, INTERNAL_ERROR.

Endpoints

Health (Unauthenticated)

MethodPathDescription
GET/healthFull health check (components + status)
GET/healthzLiveness probe (always 200)
GET/readyReadiness probe (checks dependencies)
GET/metricsPrometheus metrics endpoint

Config (Unauthenticated)

MethodPathDescription
GET/api/v1/configTenant branding + feature flags
GET/config.jsonAlias for config (frontend SPA)

Providers (Unauthenticated)

MethodPathDescription
GET/api/v1/providersProvider status for all integration subsystems (GRC, identity, FinOps, container, workflow, WAF, secrets)

Findings

MethodPathRolesPaginatedDescription
GET/api/v1/findingsviewer, operator, adminYesList findings (filters: severity, provider, status)
GET/api/v1/findings/queryviewer, operator, adminYesRQL-based finding query
POST/api/v1/findings/ingestadminNoIngest new finding (dedup cache)
GET/api/v1/findings/{id}viewer, operator, adminNoGet finding by ID (scope-enforced)
POST/api/v1/findings/{id}/enrichoperator, adminNoAI + threat intel enrichment
GET/api/v1/findings/{id}/commentsviewer, requester, operator, adminNoList finding comments
POST/api/v1/findings/{id}/commentsoperator, adminNoAdd comment to finding
DELETE/api/v1/findings/{id}/comments/{commentId}operator, adminNoDelete finding comment
POST/api/v1/findings/{id}/remediateoperator, adminNoCreate remediation ticket (integration layer)
GET/api/v1/findings/{id}/ticketoperator, adminNoGet linked ticket status
GET/api/v1/findings/{id}/ticket/commentsviewer, operator, adminNoList ticket comments (from integration)
POST/api/v1/findings/{id}/ticket/commentsoperator, adminNoAdd comment to linked ticket
POST/api/v1/findings/{id}/ticket/syncoperator, adminNoForce-refresh ticket status from integration
POST/api/v1/findings/searchoperator, adminYesKeyword, semantic, or hybrid finding search with large-corpus fallback

POST /api/v1/findings/search

Full-text and semantic search over findings. The primary path combines Bleve BM25 text search with TF-IDF embeddings via Reciprocal Rank Fusion (RRF). On large-corpus deployments where eager warmup is intentionally disabled, semantic and hybrid requests degrade to candidate-scoped in-memory reranking over keyword candidates instead of failing closed.

Request body:

{
"query": "public S3 bucket",
"mode": "hybrid",
"filters": {
"severity": ["CRITICAL", "HIGH"],
"provider": ["aws"],
"status": ["open"]
},
"page": 1,
"per_page": 50
}
FieldTypeDefaultDescription
querystring(required)Search query (max 1000 chars)
modestringhybridRequested search mode: keyword, semantic, or hybrid
filters.severitystring[](none)Filter by severity (case-insensitive)
filters.providerstring[](none)Filter by cloud provider (case-insensitive)
filters.statusstring[](none)Filter by finding status (case-insensitive)
pageint1Page number (1-indexed)
per_pageint50Results per page (max 200)

Response:

{
"data": [{ "finding": {...}, "score": 0.87 }],
"total": 42,
"page": 1,
"per_page": 50,
"max_score": 0.87,
"took_ms": 12,
"mode": "hybrid"
}

mode in the response is the effective mode used for execution. On the public 300K corpus, it may downgrade to keyword when the full search service is intentionally unavailable during startup.

POST /api/v1/findings/ingest

Ingest a new finding. Deduplication is keyed on source + source_finding_id.

Request body:

{
"source": "aws-securityhub",
"source_finding_id": "arn:aws:securityhub:us-east-1:...",
"resource_id": "arn:aws:s3:::my-bucket",
"account_id": "123456789012",
"severity": "CRITICAL",
"finding_type": "Software and Configuration Checks",
"title": "S3 bucket is publicly accessible",
"description": "The S3 bucket allows public read access..."
}
FieldTypeRequiredDescription
sourcestringyesOriginating scanner (e.g., aws-securityhub, azure-defender)
source_finding_idstringyesScanner-native finding ID for dedup
resource_idstringyesCloud resource ARN/ID
account_idstringyesCloud account ID
severitystringyesCRITICAL, HIGH, MEDIUM, LOW, INFO
finding_typestringyesFinding category
titlestringyesShort finding title
descriptionstringyesDetailed description

POST /api/v1/ai/nlq

Parse a natural language query into structured finding filters.

Request body:

{ "query": "show me critical AWS findings from last week" }

POST /api/v1/graph/query

Proxy a Gremlin or Cypher query to PuppyGraph.

Request body:

{ "language": "gremlin", "query": "g.V().hasLabel('finding').count()" }

POST /api/v1/asm/scan

Trigger an external attack surface scan for a domain.

Request body:

{ "domain": "example.com" }

POST /api/v1/webhooks

Register a new webhook endpoint.

Request body:

{
"url": "https://hooks.example.com/aegis",
"secret": "whsec_...",
"events": ["finding.created", "remediation.completed"]
}
FieldTypeRequiredDescription
urlstringyesHTTPS endpoint URL
secretstringyesHMAC signing secret
eventsstring[]noEvent filter (empty = all events)

POST /api/v1/exceptions

Create an exception request.

Request body:

{
"application_id": "app-payments",
"requestor_email": "[email protected]",
"request_type": "waiver",
"policy_violated": "REGION-001",
"resource_requested": "us-west-2 deployment for latency SLA",
"business_case": "Payment processing requires <50ms latency..."
}
FieldTypeRequiredDescription
application_idstringyesTarget application ID
policy_violatedstringyesPolicy code being excepted
requestor_emailstringnoRequestor email (validated)
request_typestringnowaiver, extension, exemption
resource_requestedstringnoWhat is being requested
business_casestringnoBusiness justification

Compliance

MethodPathRolesPaginatedDescription
GET/api/v1/compliance/frameworksviewer, operator, adminYesList compliance frameworks
GET/api/v1/compliance/postureviewer, operator, adminNoAggregated compliance posture
GET/api/v1/compliance/controls/{fw}viewer, operator, adminNoControls for a framework

Agents

MethodPathRolesPaginatedDescription
GET/api/v1/agentsviewer, operator, adminYesList security agents
GET/api/v1/agents/{id}viewer, operator, adminNoGet agent by ID
GET/api/v1/agents/{id}/tracesviewer, operator, adminNoList agent execution traces

Remediations

MethodPathRolesPaginatedDescription
GET/api/v1/remediationsviewer, operator, adminYesList remediations (filters: status, tier)
GET/api/v1/remediations/{id}viewer, operator, adminNoGet remediation by ID
POST/api/v1/remediations/{id}/executeoperator, adminNoExecute remediation
PATCH/api/v1/remediations/{id}operator, adminNoUpdate remediation status

GRC / Exceptions

MethodPathRolesPaginatedDescription
GET/api/v1/exceptions/pendingoperator, adminNoList pending exception approvals
GET/api/v1/exceptions/expiringoperator, adminNoList expiring exceptions
GET/api/v1/exceptions/minerequester, operator, adminNoList user's own exceptions
GET/api/v1/exceptions/{id}operator, adminNoGet exception by ID
POST/api/v1/exceptionsadminNoCreate new exception request
POST/api/v1/exceptions/{id}/approveadminNoSubmit approval decision
POST/api/v1/exceptions/{id}/withdrawrequester, operator, adminNoWithdraw exception
GET/api/v1/applications/{appId}/exceptionsoperator, adminNoList exceptions by app (ownership-scoped)
POST/api/v1/validate/exceptionoperator, adminNoValidate exception against policy

Policies

MethodPathRolesPaginatedDescription
GET/api/v1/policiesviewer, operator, adminYesList policies (filters: status, category)
GET/api/v1/policies/{id}viewer, operator, adminNoGet policy by ID

Attack Paths

MethodPathRolesPaginatedDescription
GET/api/v1/attack-pathsviewer, operator, adminYes (20/page, max 100)List computed attack paths
GET/api/v1/attack-paths/statsviewer, operator, adminNoAttack path statistics
GET/api/v1/attack-paths/{id}viewer, operator, adminNoGet attack path by ID
GET/api/v1/attack-paths/{id}/analysisviewer, operator, adminNoAI analysis of attack path

Costs (FinOps)

MethodPathRolesPaginatedDescription
GET/api/v1/costs/summaryviewer, operator, adminNoComputed cost summary (all providers)

Identity & Zero Trust

MethodPathRolesPaginatedDescription
GET/api/v1/identity/usersviewer, operator, adminNoList identity users (Okta/Entra ID)
GET/api/v1/identity/users/{id}/riskviewer, operator, adminNoGet user risk score
GET/api/v1/usersadminYesList platform users

Audit

MethodPathRolesPaginatedDescription
GET/api/v1/audit-logadminYesAudit log (filters: result, actor)

AI

MethodPathRolesPaginatedDescription
POST/api/v1/ai/nlqoperator, adminNoNatural language query
GET/api/v1/ai/usageadminNoAI usage/budget status

Container Security

MethodPathRolesPaginatedDescription
GET/api/v1/containersviewer, operator, adminNoList container workloads
GET/api/v1/containers/{id}viewer, operator, adminNoGet container details
GET/api/v1/container/scanoperator, adminNoScan container image
GET/api/v1/container/admissionoperator, adminNoAdmission policy check

Secrets Management

MethodPathRolesPaginatedDescription
GET/api/v1/secretsviewer, operator, adminNoList secrets (scope-guarded)
POST/api/v1/secrets/scanoperator, adminNoScan content for secrets
POST/api/v1/secrets/uploadoperator, adminNoUpload suspected secret (TLS-only, ephemeral)
GET/api/v1/secrets/{path}viewer, operator, adminNoGet secret by path (scope-guarded)
POST/api/v1/secrets/org-scanadminNoOrg-wide secrets scan

WAF

MethodPathRolesPaginatedDescription
GET/api/v1/waf/templatesviewer, operator, adminNoList WAF rule templates
GET/api/v1/waf/compliance/{templateId}viewer, operator, adminNoValidate WAF compliance

Webhooks

MethodPathRolesPaginatedDescription
POST/api/v1/webhooksoperator, adminNoRegister webhook
GET/api/v1/webhooksoperator, adminNoList webhooks
DELETE/api/v1/webhooks/{id}operator, adminNoDelete webhook
GET/api/v1/webhooks/{id}/deliveriesoperator, adminNoList webhook deliveries

Workflows

MethodPathRolesPaginatedDescription
GET/api/v1/workflowsoperator, adminNoList workflows
GET/api/v1/workflows/{id}operator, adminNoGet workflow by ID
POST/api/v1/workflows/{id}/approveoperator, adminNoApprove workflow

Deploy Preview

MethodPathRolesPaginatedDescription
POST/api/v1/deploy/previewoperator, adminNoStart deploy preview
POST/api/v1/deploy/preview/{id}/abortoperator, adminNoAbort deploy preview

Data Classification (DSPM)

MethodPathRolesPaginatedDescription
GET/api/v1/data-classification/assetsviewer, operator, adminNoList data assets with sensitivity

ASM (Attack Surface Management)

MethodPathRolesPaginatedDescription
POST/api/v1/asm/scanoperator, adminNoTrigger ASM scan
GET/api/v1/asm/assetsoperator, adminNoList discovered assets

Catalog

MethodPathRolesPaginatedDescription
GET/api/v1/catalog/modulesviewer, operator, adminYesList Terraform modules (filters: provider, category, search)

Graph Query

MethodPathRolesPaginatedDescription
POST/api/v1/graph/queryoperator, adminNoPuppyGraph Gremlin query proxy

Terminal (Operator+)

MethodPathRolesDescription
POST/api/v1/terminal/ticketoperator, adminIssue short-lived nonce for WebSocket auth (SA-002)
GET/api/v1/terminal/wsoperator, adminWebSocket upgrade for interactive terminal (auth via ?ticket= nonce or legacy ?token= JWT)

The ticket endpoint returns {"ticket": "<uuid>"} valid for 60 seconds, one-time use. The WebSocket handler validates and consumes the ticket on upgrade. Legacy ?token= JWT-in-URL is retained for backward compatibility but deprecated (leaks to logs/referrer headers).

Integration Webhooks (Unauthenticated, HMAC-verified)

MethodPathDescription
POST/api/v1/webhooks/asanaAsana webhook receiver

RBAC Roles

RoleRankDescription
viewer0Read-only access to findings, compliance, agents
requester1Viewer + exception request/withdraw
operator2Requester + write operations (remediate, enrich, scan)
admin3Full access (audit log, user management, approvals)

All endpoints require at minimum viewer role. The Require() middleware enforces minimum role rank — e.g., Require(RoleOperator, RoleAdmin) allows operator and admin but denies viewer and requester.

Note: DELETE /findings/{id}/comments/{commentId} has an additional in-handler admin-only check beyond the RBAC middleware — non-admin callers receive 403 even though the middleware passes them.

RBAC Authorization Matrix (from integration tests)

EndpointUnauthenticatedRequesterOperatorAdmin
GET /api/v1/findings401403200200
GET /api/v1/exceptions/mine401200200200
GET /api/v1/exceptions/{id}401403200200
POST /api/v1/exceptions401403200201
GET /api/v1/agents401403200200
GET /api/v1/audit-log401403200200
GET /api/v1/users401403200200
GET /api/v1/identity/users401403200200
GET /api/v1/workflows401403200200
GET /api/v1/secrets401403200200
POST /api/v1/secrets/org-scan401403403200
POST /api/v1/terminal/ticket401403200200
GET /api/v1/terminal/ws401403200200
DELETE /findings/{id}/comments/{cid}401403403204