openapi: 3.1.0
info:
  title: Superagent REST API
  version: 1.0.0
  description: |
    Create security reports, retrieve and manage findings, and start automated
    finding triage. Every request requires an organization API key.
  contact:
    url: https://superagent.sh
servers:
  - url: https://superagent.sh/api/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Findings
    description: Retrieve, update, delete, and triage security findings.
  - name: Reports
    description: Start repository and Web app security reports.
paths:
  /findings:
    get:
      operationId: listFindings
      summary: List findings
      description: Returns paginated finding summaries for the API key's organization.
      tags:
        - Findings
      parameters:
        - name: limit
          in: query
          description: Number of results to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: offset
          in: query
          description: Number of matching results to skip.
          schema:
            type: integer
            minimum: 0
            maximum: 2147483647
            default: 0
        - name: kind
          in: query
          description: Restrict results to one finding type.
          schema:
            $ref: "#/components/schemas/FindingKind"
        - name: triage_status
          in: query
          description: Restrict results to one triage state.
          schema:
            $ref: "#/components/schemas/TriageStatus"
      responses:
        "200":
          description: A page of finding summaries.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FindingListResponse"
              example:
                data:
                  - id: finding_uuid
                    object: finding
                    kind: repository_red_team
                    report_id: report_uuid
                    title: SQL injection in search endpoint
                    description: User input is interpolated into a SQL query.
                    cvss_vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
                    severity: null
                    risk_level: high
                    weakness: CWE-89
                    cwe_ids:
                      - CWE-89
                    advisory_url: null
                    source: superagent
                    status: in_review
                    triage_status: new
                    triage_resolution: null
                    board_position: 1000
                    report:
                      repository: https://github.com/acme/web
                      label: acme/web
                      status: in_review
                    created_at: "2026-07-22T07:00:00.000Z"
                    updated_at: "2026-07-22T07:00:00.000Z"
                pagination:
                  limit: 25
                  offset: 0
                  total: 1
                  has_more: false
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "500":
          $ref: "#/components/responses/InternalError"
  /findings/{finding_id}:
    parameters:
      - $ref: "#/components/parameters/FindingId"
    get:
      operationId: getFinding
      summary: Retrieve a finding
      description: Returns full triage, remediation, report, and pull-request context.
      tags:
        - Findings
      responses:
        "200":
          description: The finding.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FindingResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
    patch:
      operationId: updateFinding
      summary: Update a finding
      description: Updates the finding's manual triage lifecycle state.
      tags:
        - Findings
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateFindingRequest"
            example:
              triage_status: resolved
              triage_resolution: fixed
              board_position: 1000
      responses:
        "200":
          description: The updated finding.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FindingResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
    delete:
      operationId: deleteFinding
      summary: Delete a finding
      description: Permanently deletes a finding. This action cannot be undone.
      tags:
        - Findings
      responses:
        "204":
          description: The finding was deleted.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  /findings/{finding_id}/triage:
    parameters:
      - $ref: "#/components/parameters/FindingId"
    post:
      operationId: triggerFindingTriage
      summary: Trigger finding triage
      description: Starts billable automated triage for a finding.
      tags:
        - Findings
      responses:
        "202":
          description: Triage was accepted and queued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TriageResponse"
              example:
                data:
                  id: finding_uuid
                  object: finding
                  kind: repository_red_team
                  triage_status: triaging
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
        "500":
          $ref: "#/components/responses/InternalError"
  /reports/repository:
    post:
      operationId: createRepositoryReport
      summary: Create a repository report
      description: |
        Starts a report for a GitHub repository connected to the API key's
        organization. Sandbox provisioning continues asynchronously.
      tags:
        - Reports
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRepositoryReportRequest"
            example:
              repository: acme/web
              custom_goal_prompt: Focus on authorization boundaries.
      responses:
        "202":
          description: The report was created and accepted for provisioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RepositoryReportResponse"
              example:
                data:
                  id: report_uuid
                  object: report
                  type: repository
                  repository: https://github.com/acme/web
                  custom_goal_prompt: Focus on authorization boundaries.
                  status: in_progress
                  sandbox_status: provisioning
                  agent_status: pending
                  created_at: "2026-07-22T07:00:00.000Z"
                  updated_at: "2026-07-22T07:00:00.000Z"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalError"
  /reports/web-app:
    post:
      operationId: createWebAppReport
      summary: Create a Web app report
      description: |
        Starts a report for a public HTTP or HTTPS target. Sandbox provisioning
        continues asynchronously. Credentials and headers are never returned.
      tags:
        - Reports
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWebAppReportRequest"
            example:
              target_url: https://staging.example.com/account
              login_email: security-test@example.com
              login_password: secret
              browser_headers:
                X-Test-Environment: security
              request_throttle_rpm: 120
              custom_goal_prompt: Focus on account authorization.
      responses:
        "202":
          description: The report was created and accepted for provisioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebAppReportResponse"
              example:
                data:
                  id: report_uuid
                  object: report
                  type: web_app
                  target_url: https://staging.example.com/account
                  allowed_host: staging.example.com
                  request_throttle_rpm: 120
                  custom_goal_prompt: Focus on account authorization.
                  status: in_progress
                  sandbox_status: provisioning
                  agent_status: pending
                  created_at: "2026-07-22T07:00:00.000Z"
                  updated_at: "2026-07-22T07:00:00.000Z"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "500":
          $ref: "#/components/responses/InternalError"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Superagent API key
      description: Organization API key beginning with `sk_live_`.
  parameters:
    FindingId:
      name: finding_id
      in: path
      required: true
      description: Finding identifier.
      schema:
        type: string
  responses:
    BadRequest:
      description: The request body, field, query parameter, or state transition is invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              code: invalid_request
              message: limit must be between 1 and 100
    Unauthorized:
      description: The bearer API key is missing or invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              code: unauthorized
              message: "Provide a valid API key using Authorization: Bearer <api_key>"
    NotFound:
      description: The resource does not exist or belongs to another organization.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              code: not_found
              message: Finding not found
    Conflict:
      description: The requested work is already in progress.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              code: conflict
              message: Finding triage is already in progress
    InternalError:
      description: An unexpected server failure occurred.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            error:
              code: internal_error
              message: Internal server error
  schemas:
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              enum:
                - invalid_request
                - not_found
                - unauthorized
                - conflict
                - internal_error
            message:
              type: string
    FindingKind:
      type: string
      enum:
        - repository_red_team
        - web_app_red_team
        - github_advisory
    TriageStatus:
      type: string
      enum:
        - new
        - triaging
        - in_review
        - resolved
    ManualTriageStatus:
      type: string
      enum:
        - new
        - in_review
        - resolved
    TriageResolution:
      type: string
      enum:
        - fixed
        - accepted_risk
        - false_positive
        - wont_fix
    Pagination:
      type: object
      required:
        - limit
        - offset
        - total
        - has_more
      properties:
        limit:
          type: integer
          minimum: 1
          maximum: 100
        offset:
          type: integer
          minimum: 0
        total:
          type: integer
          minimum: 0
        has_more:
          type: boolean
    FindingReportSummary:
      type: object
      required:
        - repository
        - label
        - status
      properties:
        repository:
          type: string
          description: Repository URL, or tested target URL for a Web app finding.
        label:
          type: string
        status:
          type: string
    FindingSummary:
      type: object
      required:
        - id
        - object
        - kind
        - report_id
        - title
        - description
        - cvss_vector
        - severity
        - risk_level
        - weakness
        - cwe_ids
        - advisory_url
        - source
        - status
        - triage_status
        - triage_resolution
        - board_position
        - report
        - created_at
        - updated_at
      properties:
        id:
          type: string
        object:
          type: string
          const: finding
        kind:
          $ref: "#/components/schemas/FindingKind"
        report_id:
          type: string
        title:
          type: string
        description:
          type: string
        cvss_vector:
          type:
            - string
            - "null"
        severity:
          type:
            - string
            - "null"
        risk_level:
          type:
            - string
            - "null"
        weakness:
          type: string
        cwe_ids:
          type: array
          items:
            type: string
        advisory_url:
          type:
            - string
            - "null"
          format: uri
        source:
          type: string
        status:
          type:
            - string
            - "null"
        triage_status:
          $ref: "#/components/schemas/TriageStatus"
        triage_resolution:
          oneOf:
            - $ref: "#/components/schemas/TriageResolution"
            - type: "null"
        board_position:
          type:
            - number
            - "null"
        report:
          $ref: "#/components/schemas/FindingReportSummary"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    FindingListResponse:
      type: object
      required:
        - data
        - pagination
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/FindingSummary"
        pagination:
          $ref: "#/components/schemas/Pagination"
    AffectedProduct:
      type: object
      required:
        - ecosystem
        - packageName
        - affectedVersions
      properties:
        ecosystem:
          type: string
        packageName:
          type: string
        affectedVersions:
          type: string
    FindingTriage:
      type: object
      required:
        - status
        - resolution
        - summary
        - recommendation
        - report_markdown
        - verification_status
        - evidence
        - started_at
        - completed_at
      properties:
        status:
          $ref: "#/components/schemas/TriageStatus"
        resolution:
          oneOf:
            - $ref: "#/components/schemas/TriageResolution"
            - type: "null"
        summary:
          type:
            - string
            - "null"
        recommendation:
          type:
            - string
            - "null"
        report_markdown:
          type:
            - string
            - "null"
        verification_status:
          type:
            - string
            - "null"
          enum:
            - confirmed
            - not_reproducible
            - inconclusive
            - heuristic
            - null
        evidence:
          description: Structured evidence captured during triage.
        started_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
    ProposedPatch:
      type: object
      required:
        - summary
        - diff
        - files
      properties:
        summary:
          type: string
        diff:
          type: string
        files:
          type: array
          items:
            type: string
    CodeReference:
      type: object
      required:
        - file
        - lineStart
        - lineEnd
        - symbol
        - excerpt
        - reason
      properties:
        file:
          type: string
        lineStart:
          type:
            - integer
            - "null"
        lineEnd:
          type:
            - integer
            - "null"
        symbol:
          type:
            - string
            - "null"
        excerpt:
          type: string
        reason:
          type: string
    PullRequest:
      type: object
      required:
        - status
        - url
        - branch
        - started_at
        - completed_at
      properties:
        status:
          type: string
          enum:
            - idle
            - creating
            - created
            - failed
        url:
          type:
            - string
            - "null"
          format: uri
        branch:
          type:
            - string
            - "null"
        started_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
    FindingRemediation:
      type: object
      required:
        - proposed_patch
        - code_references
        - pull_request
      properties:
        proposed_patch:
          oneOf:
            - $ref: "#/components/schemas/ProposedPatch"
            - type: "null"
        code_references:
          type: array
          items:
            $ref: "#/components/schemas/CodeReference"
        pull_request:
          $ref: "#/components/schemas/PullRequest"
    Finding:
      type: object
      required:
        - id
        - object
        - kind
        - report_id
        - title
        - description
        - cvss_vector
        - severity
        - risk_level
        - weakness
        - cwe_ids
        - affected_products
        - advisory_url
        - source
        - status
        - triage
        - remediation
        - board_position
        - report
        - created_at
        - updated_at
      properties:
        id:
          type: string
        object:
          type: string
          const: finding
        kind:
          $ref: "#/components/schemas/FindingKind"
        report_id:
          type: string
        title:
          type: string
        description:
          type: string
        cvss_vector:
          type:
            - string
            - "null"
        severity:
          type:
            - string
            - "null"
        risk_level:
          type:
            - string
            - "null"
        weakness:
          type: string
        cwe_ids:
          type: array
          items:
            type: string
        affected_products:
          type: array
          items:
            $ref: "#/components/schemas/AffectedProduct"
        advisory_url:
          type:
            - string
            - "null"
          format: uri
        source:
          type: string
        status:
          type:
            - string
            - "null"
        triage:
          $ref: "#/components/schemas/FindingTriage"
        remediation:
          $ref: "#/components/schemas/FindingRemediation"
        board_position:
          type:
            - number
            - "null"
        report:
          $ref: "#/components/schemas/FindingReportSummary"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    FindingResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: "#/components/schemas/Finding"
    UpdateFindingRequest:
      type: object
      required:
        - triage_status
      properties:
        triage_status:
          $ref: "#/components/schemas/ManualTriageStatus"
        triage_resolution:
          oneOf:
            - $ref: "#/components/schemas/TriageResolution"
            - type: "null"
          description: Required when `triage_status` is `resolved`.
        board_position:
          description: Board position; unsupported for Web app findings.
          oneOf:
            - type: number
            - type: string
              pattern: "^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)$"
            - type: "null"
    TriageResult:
      type: object
      required:
        - id
        - object
        - kind
        - triage_status
      properties:
        id:
          type: string
        object:
          type: string
          const: finding
        kind:
          $ref: "#/components/schemas/FindingKind"
        triage_status:
          type: string
          const: triaging
    TriageResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: "#/components/schemas/TriageResult"
    CreateRepositoryReportRequest:
      type: object
      required:
        - repository
      properties:
        repository:
          type: string
          minLength: 1
          maxLength: 512
          description: Connected repository as `owner/name` or a full GitHub URL.
        custom_goal_prompt:
          type:
            - string
            - "null"
          maxLength: 8000
    CreateWebAppReportRequest:
      type: object
      required:
        - target_url
      properties:
        target_url:
          type: string
          minLength: 1
          maxLength: 2048
          format: uri
          pattern: "^https?://"
          description: |
            Public HTTP or HTTPS URL. Localhost, `.local`, and private or
            otherwise non-public IP addresses are rejected.
        login_email:
          type:
            - string
            - "null"
          maxLength: 320
        login_password:
          type:
            - string
            - "null"
          maxLength: 4096
          format: password
          writeOnly: true
        browser_headers:
          oneOf:
            - type: object
              maxProperties: 20
              propertyNames:
                type: string
                maxLength: 128
                pattern: "^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"
              additionalProperties:
                type: string
                minLength: 1
                maxLength: 4096
                pattern: "^(?!\\s*$)[^\\r\\n]+$"
            - type: "null"
          description: |
            Header names must be unique case-insensitively and use valid HTTP
            token characters. Names and values cannot be blank after trimming;
            values cannot contain line breaks.
          writeOnly: true
        request_throttle_rpm:
          oneOf:
            - type: integer
              minimum: 1
              maximum: 600
            - type: string
              pattern: "^\\s*0*(?:[1-9]|[1-9]\\d|[1-5]\\d{2}|600)\\s*$"
            - type: string
              pattern: "^\\s*$"
              description: A blank string is treated as no request limit.
            - type: "null"
        custom_goal_prompt:
          type:
            - string
            - "null"
          maxLength: 8000
    ReportCommon:
      type: object
      required:
        - id
        - object
        - status
        - sandbox_status
        - agent_status
        - created_at
        - updated_at
      properties:
        id:
          type: string
        object:
          type: string
          const: report
        status:
          type: string
        sandbox_status:
          type: string
        agent_status:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    RepositoryReport:
      allOf:
        - $ref: "#/components/schemas/ReportCommon"
        - type: object
          required:
            - type
            - repository
            - custom_goal_prompt
          properties:
            type:
              type: string
              const: repository
            repository:
              type: string
              format: uri
            custom_goal_prompt:
              type:
                - string
                - "null"
    WebAppReport:
      allOf:
        - $ref: "#/components/schemas/ReportCommon"
        - type: object
          required:
            - type
            - target_url
            - allowed_host
            - request_throttle_rpm
            - custom_goal_prompt
          properties:
            type:
              type: string
              const: web_app
            target_url:
              type: string
              format: uri
            allowed_host:
              type: string
            request_throttle_rpm:
              type:
                - integer
                - "null"
            custom_goal_prompt:
              type:
                - string
                - "null"
    RepositoryReportResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: "#/components/schemas/RepositoryReport"
    WebAppReportResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: "#/components/schemas/WebAppReport"
