> ## Documentation Index
> Fetch the complete documentation index at: https://docs.enokilabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Close a finding (mark fixed or dismiss as not an issue)

> Closes a finding from CI/CD or an agent: mark it 'fixed' or dismiss it as not an issue ('dismissed'). Every close requires an explanation, and a dismissal also requires a category (reason_code). Workspace-scoped: a finding from another workspace resolves to 404.



## OpenAPI

````yaml https://api.enokilabs.ai/openapi.json patch /api/v1/findings/{finding_id}/close
openapi: 3.1.0
info:
  title: Enoki External API
  description: >-
    Programmatic API for CI/CD integration. Authenticate with `Authorization:
    Bearer egk_...`.
  version: 0.1.0
servers: []
security: []
paths:
  /api/v1/findings/{finding_id}/close:
    patch:
      tags:
        - findings
      summary: Close a finding (mark fixed or dismiss as not an issue)
      description: >-
        Closes a finding from CI/CD or an agent: mark it 'fixed' or dismiss it
        as not an issue ('dismissed'). Every close requires an explanation, and
        a dismissal also requires a category (reason_code). Workspace-scoped: a
        finding from another workspace resolves to 404.
      operationId: api_close_finding_api_v1_findings__finding_id__close_patch
      parameters:
        - name: finding_id
          in: path
          required: true
          schema:
            type: string
            title: Finding Id
        - name: Authorization
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: Bearer token with API key
            title: Authorization
          description: Bearer token with API key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiFindingCloseRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiFindingItem'
        '404':
          description: Finding not found
        '422':
          description: Invalid status, category, or explanation
components:
  schemas:
    ApiFindingCloseRequest:
      properties:
        status:
          type: string
          enum:
            - fixed
            - dismissed
          title: Status
          description: 'Close action: ''fixed'' (resolved) or ''dismissed'' (not an issue).'
        explanation:
          type: string
          maxLength: 2000
          minLength: 1
          title: Explanation
          description: >-
            Why the finding is being closed. Required for every close: recorded
            as the fix description when 'fixed' and as the dismissal rationale
            when 'dismissed'. Maximum 2 000 characters.
        reason_code:
          anyOf:
            - type: string
              enum:
                - data_is_public
                - authenticated_users_only
                - working_as_designed
                - mitigated_elsewhere
                - accepted_risk
                - false_positive
                - other
            - type: 'null'
          title: Reason Code
          description: >-
            Dismissal category. Required when status is 'dismissed'; ignored
            otherwise. Allowed values: data_is_public, authenticated_users_only,
            working_as_designed, mitigated_elsewhere, accepted_risk,
            false_positive, other.
      type: object
      required:
        - status
        - explanation
      title: ApiFindingCloseRequest
      description: |-
        Request body to close a finding via the external API.

        Deliberately stricter than the dashboard's
        :class:`FindingStatusUpdateRequest`: a category *and* an explanation
        are mandatory for every close, so an API-driven close is always
        well-formed and carries the rationale we record as the fix
        (``fixed``) or feed back to the attacker (``dismissed``).

        - ``status`` is limited to the two close actions.
        - ``explanation`` is always required (non-empty after trimming). It
          maps to ``fix_description`` when ``fixed`` and to
          ``dismissed_reason_text`` when ``dismissed``.
        - ``reason_code`` is the dismissal *category*, typed as the
          :data:`DismissalReasonCode` literal so the allowed values are
          published in the schema and membership is enforced automatically.
          It is required when ``status`` is ``dismissed`` and unused otherwise.
    ApiFindingItem:
      properties:
        finding_id:
          type: string
          title: Finding Id
        lens:
          $ref: '#/components/schemas/Lens'
        category:
          type: string
          title: Category
        severity:
          $ref: '#/components/schemas/FindingSeverity'
        description:
          type: string
          title: Description
        expected_behavior:
          type: string
          title: Expected Behavior
        status:
          type: string
          title: Status
        created_at:
          type: string
          title: Created At
        attacks:
          items:
            $ref: '#/components/schemas/ApiAttackItem'
          type: array
          title: Attacks
      type: object
      required:
        - finding_id
        - lens
        - category
        - severity
        - description
        - expected_behavior
        - status
        - created_at
        - attacks
      title: ApiFindingItem
      description: |-
        One finding in the external API response.

        ``severity`` is typed as the canonical ``FindingSeverity`` enum so
        OpenAPI publishes the allowed values and JSON output is always
        lowercase. ``attacks`` carries the per-probe replay artefacts; the
        finding row carries only the technique-level narrative shared
        across every attack under it.
    Lens:
      type: string
      enum:
        - security
        - safety
        - quality
        - policy
      title: Lens
      description: |-
        Taxonomy partition a Finding (or test suite) is scoped to.

        Each lens is a top-level taxonomy bucket prefix. ``security`` and
        ``safety`` are the v1 lenses; ``quality`` and ``policy`` are
        reserved for future expansion. The lens drives:

        * Discriminator on the persisted ``Finding`` (security vs safety
          subtypes).
        * Security-scope enforcement at ingest (security-lens runs may
          only emit ``security.*`` categories).
        * Per-lens system prompts at the generator and retest layers.
    FindingSeverity:
      type: string
      enum:
        - critical
        - high
        - medium
        - low
      title: FindingSeverity
      description: Business-impact severity levels, ordered from most to least severe.
    ApiAttackItem:
      properties:
        attack_id:
          type: string
          title: Attack Id
        score:
          type: integer
          title: Score
        source:
          $ref: '#/components/schemas/ApiAttackSource'
        replay_script:
          items:
            $ref: '#/components/schemas/ReplayStepResponse'
          type: array
          title: Replay Script
        last_replay_status:
          type: string
          enum:
            - pending
            - succeeded
            - failed
            - inconclusive
            - stale
          title: Last Replay Status
        last_replayed_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Replayed At
        created_at:
          type: string
          title: Created At
      type: object
      required:
        - attack_id
        - score
        - source
        - replay_script
        - last_replay_status
        - created_at
      title: ApiAttackItem
      description: One attack inside a finding in the external API response.
    ApiAttackSource:
      properties:
        source_type:
          $ref: '#/components/schemas/FindingSourceType'
        assessment_id:
          type: string
          title: Assessment Id
        attack_index:
          type: integer
          title: Attack Index
        date:
          anyOf:
            - type: string
            - type: 'null'
          title: Date
      type: object
      required:
        - source_type
        - assessment_id
        - attack_index
        - date
      title: ApiAttackSource
      description: Provenance block of one attack in the external API response.
    ReplayStepResponse:
      properties:
        step:
          type: string
          enum:
            - chat
            - http
            - assert
          title: Step
        message:
          anyOf:
            - type: string
            - type: 'null'
          title: Message
        response:
          anyOf:
            - type: string
            - type: 'null'
          title: Response
        session_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Session Id
        method:
          anyOf:
            - type: string
            - type: 'null'
          title: Method
        url:
          anyOf:
            - type: string
            - type: 'null'
          title: Url
        headers:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Headers
        body:
          anyOf:
            - type: string
            - type: 'null'
          title: Body
        response_status:
          anyOf:
            - type: integer
            - type: 'null'
          title: Response Status
        response_body:
          anyOf:
            - type: string
            - type: 'null'
          title: Response Body
        target:
          anyOf:
            - type: string
            - type: 'null'
          title: Target
        assertion:
          anyOf:
            - type: string
            - type: 'null'
          title: Assertion
        expected_behavior:
          anyOf:
            - type: string
            - type: 'null'
          title: Expected Behavior
        capture_as:
          anyOf:
            - type: string
            - type: 'null'
          title: Capture As
      type: object
      required:
        - step
      title: ReplayStepResponse
      description: |-
        One replay-script step exposed via API.

        Uses a flat shape (rather than a discriminated union per type) to
        keep the wire representation simple -- the frontend reads ``step``
        to decide how to render each entry.
    FindingSourceType:
      type: string
      enum:
        - manual
        - adaptive_attacker
        - test_suite
        - drill_down
      title: FindingSourceType
      description: |-
        Pipeline that produced an ``Attack``.

        Drives source-conditional ingest behaviour: security-scope
        enforcement is gated on ``ADAPTIVE_ATTACKER`` because the SDK
        runner filters its agent prompt to ``security.*`` and the gate at
        ingest rejects out-of-scope categories. ``MANUAL`` and
        ``TEST_SUITE`` bypass that gate -- curated pentest yamls have
        already been triaged, and suite-runner findings are scoped by the
        suite's own category list. ``DRILL_DOWN`` is a synthetic
        ``assessment_id`` keyed by the drill-down run that produced the
        variant attack.

````