API reference (1.0.0-draft)
Base path /api/v1. The contract is schemas/api/openapi.yaml; this page is
rendered from it. Operations marked designed are in the contract but not implemented yet (they return 404).
Errors are application/problem+json. Out-of-scope objects return 404, never 403 (no enumeration).
ASVS
| Operation |
Request |
Permission |
Summary |
listAsvsRequirementStatus (designed) |
GET /applications/{appId}/asvs |
application.read |
|
Administration
| Operation |
Request |
Permission |
Summary |
adminListOrgUnits |
GET /admin/org-units |
org.admin |
The organization tree with member and application counts |
adminCreateOrgUnit |
POST /admin/org-units |
org.admin |
The parent must be exactly one level above (config/organization.yaml). Re-parenting is not offered. |
adminUpdateOrgUnit |
PATCH /admin/org-units/{slug} |
org.admin |
|
adminListMembers |
GET /admin/org-units/{slug}/members |
org.admin |
|
adminRemoveMember |
DELETE /admin/org-units/{slug}/members/{userId} |
org.admin |
|
adminAddMember |
PUT /admin/org-units/{slug}/members/{userId} |
org.admin |
|
adminListGrants |
GET /admin/role-assignments |
org.admin |
|
adminGrantRole |
POST /admin/role-assignments |
org.admin |
Never to yourself (403, audited); platform_admin comes from the identity provider only; scoped roles need an org unit, organization-wide roles take none. |
adminRevokeRole |
DELETE /admin/role-assignments/{grantId} |
org.admin |
|
adminListUsers |
GET /admin/users |
org.admin |
|
Applications
| Operation |
Request |
Permission |
Summary |
listApplications |
GET /applications |
application.read |
List applications in the caller's scope |
registerApplication |
POST /applications |
application.register |
Register an application from its repository contract (.security/application.yaml) |
getApplication |
GET /applications/{appId} |
application.read |
|
updateApplicationSettings (designed) |
PATCH /applications/{appId} |
application.settings.write |
Update platform-owned settings (fields owned by application.yaml are read-only here) |
getClassification |
GET /applications/{appId}/classification |
application.read |
Current classification with inputs, matched rules and explanation |
decideClassification |
POST /applications/{appId}/classification/decisions |
classification.decide |
Approve or reject the pending classification (Tier 1/2) |
requestTierOverride (designed) |
POST /applications/{appId}/classification/override-requests |
classification.request |
Request a tier different from the computed tier (downgrades need AppSec approval) |
listApplicationEnvironments (designed) |
GET /applications/{appId}/environments |
application.read |
|
listApplicationRepositories |
GET /applications/{appId}/repositories |
application.read |
|
Assessments
| Operation |
Request |
Permission |
Summary |
listAssessments |
GET /assessments |
assessment.read |
|
createAssessment |
POST /assessments |
assessment.create |
|
getAssessment |
GET /assessments/{assessmentId} |
assessment.read |
|
putAssessmentAnswers |
PUT /assessments/{assessmentId}/answers |
assessment.answer |
|
decideAssessment |
POST /assessments/{assessmentId}/decision |
assessment.approve |
Approver ≠ lead assessor; for M2 evidence the approver must be outside the owning team. Approval creates evidence. |
submitAssessment |
POST /assessments/{assessmentId}/submit |
assessment.answer |
Lead assessor submits the recorded assessment for review |
Catalogue
| Operation |
Request |
Permission |
Summary |
listCatalogueControls |
GET /catalogue/controls |
catalogue.read |
Active control catalogue (read-only; changes are made by PR, never via the API) |
Controls
| Operation |
Request |
Permission |
Summary |
listControlStates |
GET /applications/{appId}/controls |
application.read |
Current control states (app × control × scope) with requirement level |
listControlEvaluations |
GET /applications/{appId}/controls/{controlKey}/evaluations |
application.read |
Evaluation history for one control (append-only ledger) |
Evidence
| Operation |
Request |
Permission |
Summary |
listEvidence |
GET /applications/{appId}/evidence |
evidence.read |
|
listAllEvidence |
GET /evidence |
evidence.read |
Evidence across every application in scope, newest first |
listEvidenceRejections |
GET /evidence-rejections |
evidence.read |
Evidence the platform refused (forged, unapproved or tampered), newest first |
getEvidence |
GET /evidence/{evidenceId} |
evidence.read |
Evidence record with freshness history and verification details |
createEvidenceDownloadLink (designed) |
POST /evidence/{evidenceId}/download-links |
evidence.raw.read |
Short-lived download link for a raw artefact (audited) |
Exceptions
| Operation |
Request |
Permission |
Summary |
listExceptions |
GET /exceptions |
exception.read |
|
createException |
POST /exceptions |
exception.request |
Create a draft exception |
getException |
GET /exceptions/{exceptionId} |
exception.read |
|
updateDraftException (designed) |
PATCH /exceptions/{exceptionId} |
exception.request |
|
cosignException |
POST /exceptions/{exceptionId}/cosign |
exception.read |
Business-owner co-signature (Tier 1/2), before approval |
decideException |
POST /exceptions/{exceptionId}/decision |
exception.decide |
Approver must hold the required role for priority × tier and must not be the requester, technical owner or owning-team member. Tier 1/2 also require business-owner co-sign (role app_owner). |
renewException |
POST /exceptions/{exceptionId}/renewals |
exception.request |
|
revokeException |
POST /exceptions/{exceptionId}/revoke |
exception.decide |
|
submitException |
POST /exceptions/{exceptionId}/submit |
exception.request |
|
Findings
| Operation |
Request |
Permission |
Summary |
listFindings |
GET /findings |
finding.read |
|
getFinding |
GET /findings/{findingId} |
finding.read |
|
listFindingEvents |
GET /findings/{findingId}/events |
finding.read |
|
requestPriorityOverride (designed) |
POST /findings/{findingId}/priority-overrides |
finding.priority.override |
Requires approval by a second person (appsec_engineer); audited. |
listRiskAssessments |
GET /findings/{findingId}/risk-assessments |
finding.read |
Risk scoring history ("why is this P1?") |
transitionFinding |
POST /findings/{findingId}/transitions |
finding.transition |
Apply a workflow action. Closing is NOT an action; findings close only on verification evidence. |
Maturity
| Operation |
Request |
Permission |
Summary |
getApplicationMaturity |
GET /applications/{appId}/maturity |
application.read |
|
getApplicationTrend |
GET /applications/{appId}/trend |
application.read |
Monthly posture and SAMM maturity for one application (from the monthly snapshots) |
listMaturitySnapshots |
GET /maturity/snapshots |
maturity.rollup.read |
|
getOrgUnitMaturity |
GET /org-units/{orgUnitId}/maturity |
maturity.rollup.read |
Distribution of application maturity (not a league table) plus org-level Governance practices |
getOrgUnitTrend |
GET /org-units/{orgUnitId}/trend |
maturity.rollup.read |
Monthly posture and SAMM maturity for an org unit and everything below it (aggregates only) |
Organisation
| Operation |
Request |
Permission |
Summary |
listOrgUnits |
GET /org-units |
org_unit.read |
Business units and teams visible to the caller |
getOrgUnit (designed) |
GET /org-units/{orgUnitId} |
org_unit.read |
|
getCurrentUser |
GET /users/me |
authenticated |
Current caller, roles and visible scope |
| Operation |
Request |
Permission |
Summary |
listActivity |
GET /activity |
application.read |
What happened recently (evidence accepted or rejected, findings opened or closed, exceptions decided) |
getLiveness |
GET /health/live |
public |
Liveness probe |
getReadiness |
GET /health/ready |
public |
Readiness probe (DB reachable, config loaded) |
listIntegrations |
GET /integrations |
integration.read |
Every external integration, whether it is configured, what is missing, and its last run |
getJob (designed) |
GET /jobs/{jobId} |
job.read.own |
|
Reports
| Operation |
Request |
Permission |
Summary |
createReportExport (designed) |
POST /reports/exports |
report.export |
|
getOrgScorecard |
GET /reports/org-scorecard |
report.org.read |
Aggregates for leadership and executive views (no finding-level detail) |
exportReport |
GET /reports/{report}.csv |
report.export |
CSV export of open findings or control states, scoped to the caller and audited |
SBOM
| Operation |
Request |
Permission |
Summary |
listApplicationSboms |
GET /applications/{appId}/sboms |
application.read |
|
searchComponents |
GET /components |
component.read |
Search the component inventory (e.g. before a CVE is published) |
listSbomComponents |
GET /sboms/{sbomId}/components |
application.read |
|
Threat models
| Operation |
Request |
Permission |
Summary |
listThreatModels (designed) |
GET /applications/{appId}/threat-models |
application.read |
|
Tickets
| Operation |
Request |
Permission |
Summary |
listTickets (designed) |
GET /tickets |
finding.read |
|
Vulnerabilities
| Operation |
Request |
Permission |
Summary |
getVulnerability (designed) |
GET /vulnerabilities/{vulnId} |
vulnerability.read |
|
getAffectedApplications |
GET /vulnerabilities/{vulnId}/affected-applications |
vulnerability.impact.read |
Which applications are affected by this vulnerability? |
exportAffectedApplications (designed) |
POST /vulnerabilities/{vulnId}/affected-applications/exports |
vulnerability.impact.export |
Audited (data.bulk_export SIEM event when org-wide). |