Docs / findings-api

Findings API

← All docs

A finding is a single security issue identified by a probe and scored by three independent judges plus a meta-judge. Findings carry severity, framework references, evidence, and status.

GET /api/v2/findings

curl -sS "https://penaxtra.com/api/v2/findings?severity=high" \
  -H "Authorization: Bearer $TOKEN"

Required scope: findings:read. Result set capped at 200 rows; newest first.

Query parameters

ParamTypeNotes
severityenumOne of critical, high, medium, low, info.

Additional filters (endpoint_id, scan_id, framework_ref, from, to, cursor-based pagination) are planned. Today the list returns the most recent 200 rows after the severity filter.

Response

{
  "data": [
    {
      "id": "<uuid>",
      "scan_id": "<uuid>",
      "title": "Indirect prompt injection via RAG corpus",
      "severity": "high",
      "status": "open",
      "jira_issue_key": null,
      "discovered_at": "2026-05-22T10:24:01Z"
    }
  ]
}

GET /api/v2/findings/{id}

curl -sS "https://penaxtra.com/api/v2/findings/<uuid>" \
  -H "Authorization: Bearer $TOKEN"

Required scope: findings:read.

Response

{
  "id": "<uuid>",
  "scan_id": "<uuid>",
  "title": "Indirect prompt injection via RAG corpus",
  "severity": "high",
  "status": "open",
  "jira_issue_key": null,
  "discovered_at": "2026-05-22T10:24:01Z",
  "risk_refs": ["OWASP_LLM01", "MITRE_ATLAS_AML_T0051", "EU_AI_ACT_Art15"],
  "summary": "Short, redacted excerpt of the finding rationale."
}

Extended detail (evidence payload, per-judge breakdown, automated remediation hint) is planned.

Errors

CodeBodyReason
400{"error":"invalid_finding_id"}Id is missing or not a UUID.
404{"error":"finding_not_found"}Id does not belong to the caller's tenant.

PATCH /api/v2/findings/{id}

curl -sS -X PATCH "https://penaxtra.com/api/v2/findings/<uuid>" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status":"triaged"}'

Required scope: findings:write.

Accepted status values match the database constraint (migration 008):

open, triaged, fixed, false_positive, risk_accepted

Sending any other value returns 400 invalid_status.

Response

{
  "updated": true,
  "id": "<uuid>",
  "status": "triaged"
}

Errors (PATCH)

CodeBodyReason
400{"error":"bad_id"}Path id is malformed.
400{"error":"invalid_status"}Status value is not on the accepted list.
404{"error":"finding_not_found"}Id does not belong to the caller's tenant.

Audit

Every PATCH is recorded as an api.call row plus a finding.status_changed row carrying before / after status. Use the audit log API to reconcile.

Security notes

  • Findings older than the tenant's configured audit retention are pruned automatically.
  • The list endpoint does not return finding bodies; use the single-GET above for the per-row detail set.

Related

Last reviewed: 2026-06-13. Reviewed by: Engineering. Content type: Developer documentation. Reach the maintainers: [email protected] .