openapi: "3.1.0"
info:
  title: Superheld API
  version: "0.1.0-draft"
  description: |
    Draft REST API for the Superheld digital protection platform.

    This contract is currently under reconciliation with the workspace
    implementation. The running server in this workspace exposes a smaller
    and partly different surface than earlier draft product documentation.

    **Current workspace behavior:** unversioned resource paths, structured
    JSON errors, cursor pagination, device-signature ingestion, a
    prototype bearer-token secure mux, and public account auth endpoints
    for portal email/password sessions.

    Treat this file as a draft contract, not as a final compatibility
    guarantee for external integrations.

    Current workspace note: correlated Android gold-flow requests echo
    `X-Superheld-Run-Id` and `X-Superheld-Backend-Version`; structured
    JSON error responses also emit `X-Superheld-Error-Code`.
  contact:
    name: Superheld Security Team
    email: security@superheld.app
  license:
    name: Proprietary

servers:
  - url: https://sandbox.superheld.app
    description: Sandbox target under review
  - url: https://api.superheld.app
    description: Production target under review

security:
  - apiKey: []

components:
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: |
        Draft bearer-token authentication model.
        Exact production API key lifecycle, prefixes, and rotation policy
        remain under reconciliation with the current server implementation.
        The current workspace secure mux also accepts `X-API-Key`
        for the same token store.
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.superheld.app/authorize
          tokenUrl: https://auth.superheld.app/token
          scopes:
            devices:read: List and read devices
            devices:write: Register and configure devices
            threats:read: List and read threats
            alerts:read: Read derived user-visible alerts
            alerts:write: Reserved in current workspace; no alert-create route implemented
            incidents:read: Read tenant-scoped security incident records
            incidents:write: Transition tenant-scoped security incident records
            scan:write: Submit content for analysis
            events:read: Read event stream (SIEM integration)
            events:write: Submit events through the secure mux
            jobs:read: Read asynchronous job, trace, and artifact records
            jobs:write: Create and cancel asynchronous job records
            jobs:review: Review waiting asynchronous job records
            tokens:read: Read tenant-bound secure-mux token metadata
            tokens:write: Mint and revoke tenant-bound secure-mux tokens
            status:read: Read protection status
            webhooks:read: List webhook configurations
            webhooks:write: Create webhook configurations
        clientCredentials:
          tokenUrl: https://auth.superheld.app/token
          scopes:
            devices:read: List and read devices
            threats:read: List and read threats
            events:read: Read event stream
            incidents:read: Read tenant-scoped security incident records
            incidents:write: Transition tenant-scoped security incident records
            jobs:read: Read asynchronous job, trace, and artifact records
            jobs:review: Review waiting asynchronous job records
            tokens:read: Read tenant-bound secure-mux token metadata
            tokens:write: Mint and revoke tenant-bound secure-mux tokens
            alerts:read: Read derived user-visible alerts
            status:read: Read protection status
            webhooks:read: List webhook configurations
    deviceSignature:
      type: apiKey
      in: header
      name: X-Device-Signature
      description: |
        RSA-PSS + SHA-256 signature over the request body,
        base64-encoded. Used by device agents to authenticate
        event submissions. Requires prior device registration
        with public key via POST /devices.

  parameters:
    cursor:
      name: cursor
      in: query
      schema:
        type: string
      description: Pagination cursor from previous response
    limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      description: Number of items per page (default 20, max 100; /events allows max 500)

  schemas:
    ThreatCategory:
      type: string
      enum:
        - phone_scam
        - social_engineering
        - malicious_app
        - phishing
        - remote_control
        - deepfake

    Severity:
      type: string
      enum: [low, medium, high, critical]

    ActionTaken:
      type: string
      enum: [allow, warn, block]

    AccountRegisterRequest:
      type: object
      required: [email, password, tenant_id]
      additionalProperties: false
      properties:
        email:
          type: string
          format: email
          example: "familie@example.com"
        password:
          type: string
          minLength: 12
          example: "correct horse battery"
        tenant_id:
          type: string
          example: "tenant-local"

    AccountLoginRequest:
      type: object
      required: [email, password]
      additionalProperties: false
      properties:
        email:
          type: string
          format: email
          example: "familie@example.com"
        password:
          type: string
          example: "correct horse battery"

    AccountSession:
      type: object
      required: [account_id, tenant_id, email, token, token_id, scopes, created_at]
      additionalProperties: false
      properties:
        account_id:
          type: string
          example: "acct_e253c17a15872e72"
        tenant_id:
          type: string
          example: "tenant-local"
        email:
          type: string
          format: email
          example: "familie@example.com"
        token:
          type: string
          example: "shk_fd8cadaa42e74db906eb95c50f1bc1734c3a044100432f79"
        token_id:
          type: string
          example: "tok_57265ef0b8c03396"
        scopes:
          type: array
          items:
            type: string
          example: [status:read, devices:read, alerts:read, incidents:read, tokens:read, tokens:write]
        created_at:
          type: string
          format: date-time
          example: "2026-03-18T20:29:23Z"

    Device:
      type: object
      required: [device_id, tenant_id, platform, status, public_key_b64]
      properties:
        device_id:
          type: string
          description: "Unique device identifier. Format: `dev_...`"
          example: "dev_3c8a1f"
        tenant_id:
          type: string
          description: Tenant identifier bound to the device registration
        platform:
          type: string
          enum: [ios, android, windows, macos, linux]
        agent_version:
          type: string
          example: "2.4.1"
        last_seen:
          type: string
          format: date-time
        status:
          type: string
          enum: [active, revoked]
        name:
          type: string
          description: User-assigned display name
        public_key_b64:
          type: string
          description: Base64-encoded DER public key for device signature verification

    Threat:
      type: object
      required: [threat_id, threat_category, confidence, severity, device_id, detected_at, status]
      properties:
        threat_id:
          type: string
          description: "Unique threat identifier. Format: `thr_...`"
          example: "thr_8f3a2b"
        threat_category:
          $ref: "#/components/schemas/ThreatCategory"
        confidence:
          type: number
          format: float
          minimum: 0.0
          maximum: 1.0
          example: 0.92
        severity:
          $ref: "#/components/schemas/Severity"
        device_id:
          type: string
          example: "dev_3c8a1f"
        detected_at:
          type: string
          format: date-time
        description:
          type: string
        indicators:
          type: array
          items:
            type: string
          description: IOCs (SHA-256 hashes, signature IDs)
        status:
          type: string
          enum: [active, resolved, dismissed]

    Event:
      type: object
      required: [event_id, type, tenant_id, timestamp, device_id, threat_category, confidence, action_taken, policy_id, severity]
      properties:
        event_id:
          type: string
          description: "Unique event identifier. Format: `evt_...`"
          example: "evt_7f2a9c"
        type:
          type: string
          description: Current workspace event type discriminator
          example: "risk.event.created"
        tenant_id:
          type: string
          description: Tenant binding used for authorization and webhook dispatch
        timestamp:
          type: string
          format: date-time
        device_id:
          type: string
        threat_category:
          $ref: "#/components/schemas/ThreatCategory"
        confidence:
          type: number
          format: float
          minimum: 0.0
          maximum: 1.0
        action_taken:
          $ref: "#/components/schemas/ActionTaken"
        policy_id:
          type: string
          description: "Format: `pol_...`"
        severity:
          $ref: "#/components/schemas/Severity"
        description:
          type: string
        indicators:
          type: array
          items:
            type: string
        metadata:
          $ref: "#/components/schemas/EventMetadata"

    EventMetadata:
      type: object
      properties:
        agent_version:
          type: string
          example: "2.4.1"
        model_version:
          type: string
          example: "detect-v3.2"
        device_platform:
          type: string
          enum: [ios, android, windows, macos, linux]
        tenant_id:
          type: string
          description: "Organization identifier. Format: `org_...`"
          example: "org_5e9d2a"

    Alert:
      type: object
      required: [alert_id, tenant_id, device_id, status, severity, title, event_ids]
      properties:
        alert_id:
          type: string
        tenant_id:
          type: string
        device_id:
          type: string
        status:
          type: string
          enum: [open]
        severity:
          $ref: "#/components/schemas/Severity"
        title:
          type: string
        event_ids:
          type: array
          items:
            type: string

    Incident:
      type: object
      required: [id, tenant_id, category, severity, status, message]
      properties:
        id:
          type: string
        tenant_id:
          type: string
        category:
          type: string
        severity:
          $ref: "#/components/schemas/Severity"
        status:
          type: string
          enum: [open, investigating, contained, resolved]
        message:
          type: string

    Webhook:
      type: object
      required: [id, tenant_id, url]
      properties:
        id:
          type: string
        tenant_id:
          type: string
        url:
          type: string
          format: uri
        last_delivery_status:
          type: integer
          description: Last observed webhook HTTP status code, if any
        last_delivery_error:
          type: string
          description: Last observed delivery error message, if any
        last_delivery_at:
          type: string
          format: date-time
          description: Timestamp of the last delivery attempt
        last_delivery_attempts:
          type: integer
          minimum: 0
          description: Number of attempts made for the last recorded delivery

    WebhookCreate:
      type: object
      required: [tenant_id, url, secret]
      properties:
        tenant_id:
          type: string
          description: Tenant binding for this webhook configuration
        url:
          type: string
          format: uri
        secret:
          type: string
          description: Shared secret for HMAC-SHA256 webhook signature

    ScanRequest:
      type: object
      description: Submit a URL or SHA-256 hash for threat analysis. At least one field is required.
      anyOf:
        - required: [url]
        - required: [hash]
      properties:
        url:
          type: string
          format: uri
          description: URL to analyze
        hash:
          type: string
          description: SHA-256 hash to check against threat database

    ScanResult:
      type: object
      required: [scan_id, status, threat_detected]
      properties:
        scan_id:
          type: string
          description: "Format: `scn_...`"
          example: "scn_4e7d1c"
        status:
          type: string
          enum: [completed, pending, error]
        threat_detected:
          type: boolean
        threat_type:
          $ref: "#/components/schemas/ThreatCategory"
        confidence:
          type: number
          format: float
          minimum: 0.0
          maximum: 1.0
        details:
          type: string

    ProtectionStatus:
      type: object
      required: [total_devices, active_devices, total_events, active_threats, status]
      properties:
        total_devices:
          type: integer
        active_devices:
          type: integer
        total_events:
          type: integer
        active_threats:
          type: integer
        status:
          type: string
          enum: [protected, threats_detected, no_devices]
          description: |
            Overall protection status:
            - `protected`: all devices active, no active threats
            - `threats_detected`: active threats present
            - `no_devices`: no devices registered
    IdentityRef:
      type: object
      additionalProperties: false
      properties:
        type:
          type: string
        id:
          type: string

    JobCreate:
      type: object
      required: [job_class, workflow_id, input_refs]
      additionalProperties: false
      properties:
        tenant_id:
          type: string
        job_class:
          type: string
          example: investigation
        workflow_id:
          type: string
          example: incident_triage_v1
        input_refs:
          type: object
          description: For the current runtime workflow `incident_triage_v1`, a non-empty `event_ids` array is required.
          example:
            event_ids: [evt_01, evt_02]
          additionalProperties:
            type: array
            items:
              type: string
        initiated_by:
          $ref: "#/components/schemas/IdentityRef"
        max_runs:
          type: integer
          minimum: 1

    JobReview:
      type: object
      required: [action]
      additionalProperties: false
      properties:
        action:
          type: string
          enum: [approve, amend, reject, cancel]
        comment:
          type: string
        amendments:
          type: object
          description: Current runtime supports `input_refs` and `max_runs` only.
          additionalProperties: true

    Job:
      type: object
      required: [job_id, tenant_id, job_class, workflow_id, status]
      additionalProperties: false
      properties:
        job_id:
          type: string
        tenant_id:
          type: string
        job_class:
          type: string
        workflow_id:
          type: string
        status:
          type: string
          enum: [queued, running, waiting_review, succeeded, failed_retryable, failed_terminal, cancelled, expired]
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        initiated_by:
          $ref: "#/components/schemas/IdentityRef"
        reviewed_by:
          $ref: "#/components/schemas/IdentityRef"
        input_refs:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
        artifact_refs:
          type: array
          items:
            type: string
        trace_id:
          type: string
        current_run:
          type: integer
        max_runs:
          type: integer

    JobListResponse:
      type: object
      required: [data, has_more]
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Job"
        has_more:
          type: boolean
        cursor:
          type: string

    IncidentListResponse:
      type: object
      required: [data, has_more]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Incident"
        has_more:
          type: boolean
        cursor:
          type: string

    Artifact:
      type: object
      required: [artifact_id, job_id, tenant_id, artifact_type]
      additionalProperties: false
      properties:
        artifact_id:
          type: string
        job_id:
          type: string
        tenant_id:
          type: string
        artifact_type:
          type: string
        created_at:
          type: string
          format: date-time
        summary:
          type: string
        why_it_matters:
          type: string
        evidence_refs:
          type: array
          items:
            type: string
        recommended_next:
          type: array
          items:
            type: string

    ArtifactListResponse:
      type: object
      required: [data]
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Artifact"

    Trace:
      type: object
      required: [trace_id, job_id, tenant_id, workflow_id]
      additionalProperties: false
      properties:
        trace_id:
          type: string
        job_id:
          type: string
        tenant_id:
          type: string
        workflow_id:
          type: string
        initiated_by:
          $ref: "#/components/schemas/IdentityRef"
        started_at:
          type: string
          format: date-time
        finished_at:
          type: string
          format: date-time
        final_status:
          type: string
        artifact_refs:
          type: array
          items:
            type: string

    TraceStep:
      type: object
      required: [step_id, trace_id, job_id, tenant_id, step_type, status]
      additionalProperties: false
      properties:
        step_id:
          type: string
        trace_id:
          type: string
        job_id:
          type: string
        tenant_id:
          type: string
        step_type:
          type: string
        status:
          type: string
        started_at:
          type: string
          format: date-time
        finished_at:
          type: string
          format: date-time
        guardrail_result:
          type: string
        error_code:
          type: string

    TraceStepListResponse:
      type: object
      required: [data]
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TraceStep"

    ManagedToken:
      type: object
      required: [token_id, tenant_id, scopes, created_at]
      additionalProperties: false
      properties:
        token_id:
          type: string
        tenant_id:
          type: string
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        expires_at:
          type: ["string", "null"]
          format: date-time

    ManagedTokenCreate:
      type: object
      required: [scopes]
      additionalProperties: false
      properties:
        scopes:
          type: array
          minItems: 1
          items:
            type: string
        expires_at:
          type: string
          format: date-time

    ManagedTokenIssued:
      type: object
      required: [token_id, tenant_id, scopes, created_at, token]
      additionalProperties: false
      properties:
        token_id:
          type: string
        tenant_id:
          type: string
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        expires_at:
          type: ["string", "null"]
          format: date-time
        token:
          type: string

    ManagedTokenListResponse:
      type: object
      required: [data, has_more]
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ManagedToken"
        has_more:
          type: boolean
        cursor:
          type: string

    AuditEntry:
      type: object
      required: [id, timestamp, action, subject, detail, hash, prev_hash]
      additionalProperties: false
      properties:
        id:
          type: string
        timestamp:
          type: string
          format: date-time
        action:
          type: string
        subject:
          type: string
        detail:
          type: string
        fields:
          type: object
          additionalProperties:
            type: string
          description: Parsed key/value fields derived from the current audit detail format when available.
        hash:
          type: string
        prev_hash:
          type: string

    AuditEntryListResponse:
      type: object
      required: [data]
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AuditEntry"

    WebhookPayload:
      type: object
      description: |
        Webhook delivery includes HMAC-SHA256 signature headers:
        - `X-Superheld-Signature`: HMAC-SHA256 over `{timestamp}.{body}`
        - `X-Superheld-Timestamp`: Unix timestamp of signature

        Consumers should reject payloads older than 5 minutes.
        Current workspace retry policy: 3 total attempts with exponential backoff (1s, 2s, 4s).

    WebhookDlqEntry:
      type: object
      required: [id, webhook_id, payload, attempts, last_attempt]
      properties:
        id:
          type: string
        webhook_id:
          type: string
        payload:
          type: string
          format: byte
        status_code:
          type: integer
        error:
          type: string
        attempts:
          type: integer
        last_attempt:
          type: string
          format: date-time

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message, status]
          properties:
            code:
              type: string
              example: "insufficient_scope"
            message:
              type: string
              example: "Scope 'threats:read' required for this endpoint."
            status:
              type: integer
              example: 403

  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error:
              code: "invalid_parameter"
              message: "Parameter 'limit' must be between 1 and 100."
              status: 400
    Unauthorized:
      description: Authentication failed
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error:
              code: "unauthorized"
              message: "Invalid or expired API key."
              status: 401
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error:
              code: "insufficient_scope"
              message: "Scope 'threats:read' required for this endpoint."
              status: 403
    RateLimited:
      description: Rate limit exceeded (120 req/min)
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
            example: 120
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-RateLimit-Reset:
          schema:
            type: integer
            description: Unix timestamp when the rate limit window resets
        Retry-After:
          schema:
            type: integer
            description: Seconds until the rate limit resets
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error:
              code: "rate_limited"
              message: "Rate limit exceeded. Retry after X-RateLimit-Reset."
              status: 429
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error:
              code: "not_found"
              message: "The requested resource was not found."
              status: 404

paths:
  # ──────────────────────────────────────────────────────────────
  # CURRENT WORKSPACE-IMPLEMENTED ENDPOINTS
  # ──────────────────────────────────────────────────────────────

  /account/register:
    post:
      operationId: registerAccount
      summary: Register end-user account
      description: |
        Create an account for the portal and issue a tenant-scoped opaque
        bearer token. The current runtime requires `email`, `tenant_id`,
        and a password with at least 12 characters.
      tags: [Auth]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AccountRegisterRequest"
      responses:
        "201":
          description: Account created and session issued
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccountSession"
        "400":
          $ref: "#/components/responses/BadRequest"
        "409":
          description: Account already exists for this email
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /account/login:
    post:
      operationId: loginAccount
      summary: Authenticate end-user account
      description: |
        Authenticate a stored email/password pair and issue a fresh
        tenant-scoped opaque bearer token for the account portal.
      tags: [Auth]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AccountLoginRequest"
      responses:
        "200":
          description: Session issued
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AccountSession"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /devices:
    get:
      operationId: listDevices
      summary: List registered devices
      description: Returns all devices registered to the authenticated organization.
      tags: [Devices]
      security:
        - apiKey: []
        - oauth2: ['devices:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
        - name: action
          in: query
          required: false
          schema:
            type: string
          description: Filter job review audit entries by recorded review action
        - name: reviewed_by
          in: query
          required: false
          schema:
            type: string
          description: Filter job review audit entries by reviewer token identifier
      responses:
        "200":
          description: List of devices
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Device"
                  has_more:
                    type: boolean
                  cursor:
                    type: string
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      operationId: registerDevice
      summary: Register a new device
      description: |
        Register a device agent. The request must include the device's
        public key (base64-encoded DER) for subsequent event signature
        verification.
      tags: [Devices]
      security:
        - apiKey: []
        - oauth2: ['devices:write']
      parameters:
        - in: header
          name: X-Device-Signature
          required: true
          schema:
            type: string
          description: |
            Base64-encoded RSA-PSS + SHA-256 signature over the exact
            JSON request body. The signature must verify against the
            `public_key_b64` supplied in the same payload.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [device_id, tenant_id, platform, status, public_key_b64]
              properties:
                device_id:
                  type: string
                tenant_id:
                  type: string
                platform:
                  type: string
                  enum: [ios, android, windows, macos, linux]
                status:
                  type: string
                  enum: [active, revoked]
                public_key_b64:
                  type: string
                  description: Base64-encoded DER public key (RSA PKIX / SubjectPublicKeyInfo)
                name:
                  type: string
      responses:
        "201":
          description: Device registered
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Device"
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"

  /threats:
    get:
      operationId: listThreats
      summary: List detected threats
      description: |
        Derived entity view: latest state per threat, deduplicated by
        (device_id, threat_category). For the canonical append-only
        event stream, use `GET /events`.
      tags: [Threats]
      security:
        - apiKey: []
        - oauth2: ['threats:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
        - name: since
          in: query
          schema:
            type: string
            format: date-time
          description: Filter threats detected after this timestamp (ISO 8601)
        - name: severity
          in: query
          schema:
            $ref: "#/components/schemas/Severity"
        - name: device_id
          in: query
          schema:
            type: string
          description: Filter by device
      responses:
        "200":
          description: List of threats
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Threat"
                  has_more:
                    type: boolean
                  cursor:
                    type: string
                  total_count:
                    type: integer
              example:
                data:
                  - threat_id: "thr_8f3a2b"
                    threat_category: "phishing"
                    severity: "high"
                    confidence: 0.92
                    device_id: "dev_3c8a1f"
                    detected_at: "2026-03-14T09:22:17Z"
                    description: "Gefälschte Login-Seite erkannt"
                    status: "active"
                has_more: true
                total_count: 42
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /events:
    get:
      operationId: listEvents
      summary: List detection events
      description: |
        Canonical append-only event stream. Every detection decision (allow,
        warn, block) is recorded as an immutable event. Primary integration
        endpoint for SIEM systems and polling-based integrations.
        Maximum page size: 500.
      tags: [Events]
      security:
        - apiKey: []
        - oauth2: ['events:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 20
          description: Number of events per page (max 500)
        - name: since
          in: query
          schema:
            type: string
            format: date-time
          description: Filter events after this timestamp (ISO 8601)
        - name: severity
          in: query
          schema:
            $ref: "#/components/schemas/Severity"
        - name: threat_category
          in: query
          schema:
            $ref: "#/components/schemas/ThreatCategory"
      responses:
        "200":
          description: List of events
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Event"
                  has_more:
                    type: boolean
                  cursor:
                    type: string
              example:
                data:
                  - event_id: "evt_7f2a9c"
                    type: "risk.event.created"
                    timestamp: "2026-03-14T14:32:08Z"
                    tenant_id: "tenant-acme"
                    device_id: "dev_3c8a1f"
                    threat_category: "phishing"
                    confidence: 0.94
                    action_taken: "block"
                    policy_id: "pol_default"
                    severity: "high"
                    description: "Gefälschte Login-Seite erkannt und blockiert."
                    indicators: ["sha256:a1b2c3d4e5f6..."]
                    metadata:
                      agent_version: "2.4.1"
                      model_version: "detect-v3.2"
                      device_platform: "macos"
                has_more: false
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      operationId: submitEvent
      summary: Submit a detection event
      description: |
        Submit a detection event from a device agent. Requires
        `X-Device-Signature` header with RSA-PSS + SHA-256
        signature over the request body. The device must be
        registered with its public key via `POST /devices`.
        Replay protection: duplicate `event_id` values are rejected (409).
      tags: [Events]
      security:
        - deviceSignature: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Event"
      responses:
        "202":
          description: Event accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Event"
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "409":
          description: Duplicate event_id (replay protection)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /alerts:
    get:
      operationId: listAlerts
      summary: List derived alerts
      description: |
        Returns user-visible alerts derived from accepted event records.
        The default first page returns the most recent alerts (newest first),
        consistent with GET /incidents.
        This workspace does not currently expose alert rule management via `/alerts`.
      tags: [Alerts]
      security:
        - apiKey: []
        - oauth2: ['alerts:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
        - name: severity
          in: query
          schema:
            $ref: "#/components/schemas/Severity"
        - name: status
          in: query
          schema:
            type: string
            enum: [open]
        - name: device_id
          in: query
          schema:
            type: string
        - name: tenant_id
          in: query
          schema:
            type: string
      responses:
        "200":
          description: List of alerts
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Alert"
                  has_more:
                    type: boolean
                  cursor:
                    type: string
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /incidents:
    get:
      operationId: listIncidents
      summary: List tenant-scoped security incidents
      description: |
        Returns read-only security incident records derived from accepted
        high-severity alerting events and high-severity security monitor
        observations in the current runtime.
        The current workspace stores incidents in memory by default and can
        persist them to local JSON or SQLite when configured.
      tags: [Incidents]
      security:
        - apiKey: []
        - oauth2: ['incidents:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: List of security incidents
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IncidentListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /incidents/{incident_id}:
    get:
      operationId: getIncident
      summary: Read one tenant-scoped security incident
      description: |
        Returns one read-only security incident record derived from accepted
        high-severity alerting events and high-severity security monitor
        observations in the current runtime.
      tags: [Incidents]
      security:
        - apiKey: []
        - oauth2: ['incidents:read']
      parameters:
        - name: incident_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Incident detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Incident"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    patch:
      operationId: transitionIncident
      summary: Transition one tenant-scoped security incident
      description: |
        Applies the current runtime incident lifecycle rules.
        Supported transitions are `open -> investigating/resolved`,
        `investigating -> contained/resolved`, and `contained -> resolved`.
      tags: [Incidents]
      security:
        - apiKey: []
        - oauth2: ['incidents:write']
      parameters:
        - name: incident_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status]
              additionalProperties: false
              properties:
                status:
                  type: string
                  enum: [investigating, contained, resolved]
      responses:
        "200":
          description: Updated incident detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Incident"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /scan:
    post:
      operationId: submitScan
      summary: Submit content for analysis
      description: Submit a URL or SHA-256 hash for threat analysis. At least one of `url` or `hash` is required.
      tags: [Scan]
      security:
        - apiKey: []
        - oauth2: ['scan:write']
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ScanRequest"
            example:
              url: "https://example-phishing.com/login"
      responses:
        "200":
          description: Scan result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ScanResult"
              example:
                scan_id: "scn_4e7d1c"
                status: "completed"
                threat_detected: true
                threat_type: "phishing"
                confidence: 0.97
                details: "Domain imitiert bekannten Finanzdienstleister. SSL-Zertifikat seit 2 Tagen aktiv."
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"

  /status:
    get:
      operationId: getStatus
      summary: Get protection status
      description: Returns overall protection status across all registered devices.
      tags: [Status]
      security:
        - apiKey: []
        - oauth2: ['status:read']
      responses:
        "200":
          description: Protection status
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProtectionStatus"
              example:
                total_devices: 12
                active_devices: 11
                total_events: 847
                active_threats: 3
                status: "threats_detected"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /jobs:
    get:
      operationId: listJobs
      summary: List asynchronous job records
      description: |
        List tenant-scoped asynchronous job records. The current workspace
        runtime supports the deterministic `incident_triage_v1` workflow and
        also exposes `GET /jobs/{id}`, `POST /jobs/{id}/review`,
        `GET /jobs/{id}/steps`, `GET /jobs/{id}/artifacts`,
        `GET /artifacts/{id}`, `GET /traces/{id}`, and
        `GET /traces/{id}/steps`.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Job list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JobListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      operationId: createJob
      summary: Create asynchronous job record
      description: |
        Create an asynchronous job record and queue it for runtime processing.
        In the current workspace this is a constrained prototype that
        currently supports `incident_triage_v1` as the first deterministic
        workflow and produces internal artifacts after execution.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:review']
        - oauth2: ['jobs:write']
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/JobCreate"
      responses:
        "201":
          description: Job created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Job"
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"

  /jobs/{job_id}:
    get:
      operationId: getJob
      summary: Get asynchronous job record
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Job detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Job"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /jobs/{job_id}/cancel:
    post:
      operationId: cancelJob
      summary: Cancel one asynchronous job
      description: |
        Cancel a queued, running, or waiting-review job. The current
        workspace runtime returns the updated job record and rejects
        invalid state transitions with `409`.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:write']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cancelled job detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Job"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: Job cannot be cancelled from current state

  /jobs/{job_id}/review:
    post:
      operationId: reviewJob
      summary: Review one asynchronous job
      description: |
        Review a waiting-review job. The current workspace runtime accepts
        the dedicated `jobs:review` scope and continues to accept `jobs:write`
        for backward compatibility. `approve`, `amend`, `reject`, and `cancel`
        are supported. `approve` and `amend` re-queue the job for execution.
        Current runtime amendments support `input_refs` and `max_runs` only.
        Invalid state transitions return `422`.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:write']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/JobReview"
      responses:
        "200":
          description: Reviewed job detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Job"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          description: Job is not waiting for review

  /jobs/audit:
    get:
      operationId: listJobAudit
      summary: List tenant-scoped audit entries across reviewed jobs
      description: |
        Read tenant-scoped job review audit entries across all visible job
        subjects. This is currently an internal/operator-facing runtime path.
        When the runtime uses JSON or SQLite persistence, the job audit trail
        follows the same backend.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Job audit entries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditEntryListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /jobs/{job_id}/audit:
    get:
      operationId: getJobAudit
      summary: Get audit entries for one job
      description: |
        Read tenant-scoped audit entries recorded for one reviewed job
        subject. This is currently an internal/operator-facing runtime path.
        When the runtime uses JSON or SQLite persistence, the job audit trail
        follows the same backend.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Job audit entries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditEntryListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /jobs/{job_id}/steps:
    get:
      operationId: listJobSteps
      summary: List steps for a job
      description: Current runtime step types can include `review_decision` when a waiting job is reviewed.
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Step list for job
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TraceStepListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /jobs/{job_id}/artifacts:
    get:
      operationId: listJobArtifacts
      summary: List artifacts for a job
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: job_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Artifact list for job
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ArtifactListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /artifacts/{artifact_id}:
    get:
      operationId: getArtifact
      summary: Get artifact
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: artifact_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Artifact detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Artifact"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /traces/{trace_id}:
    get:
      operationId: getTrace
      summary: Get trace
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: trace_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Trace detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Trace"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /traces/{trace_id}/steps:
    get:
      operationId: listTraceSteps
      summary: List steps for a trace
      tags: [Jobs]
      security:
        - apiKey: []
        - oauth2: ['jobs:read']
      parameters:
        - name: trace_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Step list for trace
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TraceStepListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /tokens:
    get:
      operationId: listTokens
      summary: List tenant-bound secure-mux token metadata
      description: |
        List tenant-bound secure-mux token metadata records. This is a
        current workspace operator/runtime prototype and not yet a final
        public product lifecycle contract.
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Token list
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagedTokenListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      operationId: createToken
      summary: Mint tenant-bound secure-mux token
      description: |
        Mint a tenant-bound secure-mux token. The raw token value is only
        returned once at creation time. Requested scopes must be a subset of
        the caller's current scopes.
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:write']
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagedTokenCreate"
      responses:
        "201":
          description: Token created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagedTokenIssued"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: Requested scopes exceeded caller permissions

  /tokens/{token_id}:
    get:
      operationId: getToken
      summary: Get one tenant-bound secure-mux token metadata record
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:read']
      parameters:
        - name: token_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Token detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagedToken"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      operationId: deleteToken
      summary: Revoke one tenant-bound secure-mux token
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:write']
      parameters:
        - name: token_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Token revoked
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /tokens/audit:
    get:
      operationId: listTokenAudit
      summary: List tenant-scoped audit entries across secure-mux tokens
      description: |
        Read tenant-scoped token lifecycle audit entries across all visible
        token subjects. This is currently an internal/operator-facing runtime
        path. When the runtime uses JSON or SQLite persistence, the token
        audit trail follows the same backend.
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
        - name: action
          in: query
          required: false
          schema:
            type: string
          description: Filter token audit entries by recorded lifecycle action
        - name: token_id
          in: query
          required: false
          schema:
            type: string
          description: Filter token audit entries by token subject identifier
      responses:
        "200":
          description: Token audit entries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditEntryListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /tokens/{token_id}/audit:
    get:
      operationId: getTokenAudit
      summary: Get audit entries for one tenant-bound secure-mux token
      description: |
        Read tenant-scoped audit entries recorded for one token subject.
        This is currently an internal/operator-facing runtime path. When the
        runtime uses JSON or SQLite persistence, the token audit trail follows
        the same backend.
      tags: [Auth]
      security:
        - apiKey: []
        - oauth2: ['tokens:read']
      parameters:
        - name: token_id
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: Token audit entries
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditEntryListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"

  /webhooks:
    get:
      operationId: listWebhooks
      summary: List webhook configurations
      tags: [Webhooks]
      security:
        - apiKey: []
        - oauth2: ['webhooks:read']
      parameters:
        - $ref: "#/components/parameters/cursor"
        - $ref: "#/components/parameters/limit"
      responses:
        "200":
          description: List of webhooks
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Webhook"
                  has_more:
                    type: boolean
                  cursor:
                    type: string
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      operationId: createWebhook
      summary: Create webhook configuration
      description: |
        Register a webhook endpoint. Deliveries include HMAC-SHA256
        signature via `X-Superheld-Signature` header. Failed deliveries
        are currently retried up to 3 total attempts with exponential backoff.
        Retries are attempted for `429`, `5xx`, and transport failures.
        The current workspace runtime only accepts `https://` targets and
        rejects loopback, link-local, and private destination addresses,
        including redirect targets.
        Persisted webhook secrets require `SUPERHELD_SECRET_KEY_B64` in the
        current workspace runtime; otherwise the runtime falls back to an
        in-memory webhook store instead of writing plaintext secrets to disk.
      tags: [Webhooks]
      security:
        - apiKey: []
        - oauth2: ['webhooks:write']
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookCreate"
      responses:
        "201":
          description: Webhook created. Secret is stored but not returned in the response body.
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"

  /webhooks/dlq:
    get:
      operationId: listWebhookDlq
      summary: List webhook DLQ entries
      description: |
        List retained failed webhook deliveries. In the current workspace
        this is tenant-scoped in the secure mux.
      tags: [Webhooks]
      security:
        - apiKey: []
        - oauth2: ['webhooks:read']
      responses:
        "200":
          description: List of retained webhook DLQ entries
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/WebhookDlqEntry"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      operationId: replayWebhookDlq
      summary: Replay a retained DLQ item
      description: |
        Replay a retained DLQ item. The current workspace accepts either a
        specific `entry_id` or, for backwards compatibility, a `webhook_id`
        that resolves to the latest retained entry for that webhook. The
        workspace reuses the existing retry pipeline and records the resulting
        delivery metadata back to the webhook configuration.
      tags: [Webhooks]
      security:
        - apiKey: []
        - oauth2: ['webhooks:write']
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              anyOf:
                - required: [entry_id]
                - required: [webhook_id]
              properties:
                entry_id:
                  type: string
                  description: Specific DLQ entry to replay
                webhook_id:
                  type: string
                  description: Replay the latest retained DLQ entry for this webhook
      responses:
        "200":
          description: Replay executed
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  result:
                    $ref: "#/components/schemas/WebhookDlqEntry"
        "400":
          $ref: "#/components/responses/BadRequest"
        "413":
          description: Request body exceeded the current runtime limit
        "401":
          $ref: "#/components/responses/Unauthorized"
    delete:
      operationId: deleteWebhookDlqEntry
      summary: Delete a retained DLQ item
      description: |
        Remove a retained DLQ item after manual review or successful out-of-band
        remediation. The current workspace requires the `entry_id` query
        parameter.
      tags: [Webhooks]
      security:
        - apiKey: []
        - oauth2: ['webhooks:write']
      parameters:
        - in: query
          name: entry_id
          required: true
          schema:
            type: string
      responses:
        "200":
          description: DLQ entry deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  entry_id:
                    type: string
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /guidance:
    get:
      operationId: getGuidance
      summary: Read guidance endpoint
      description: |
        Returns guidance content for the authenticated tenant.
      tags: [Status]
      security:
        - apiKey: []
        - oauth2: ['guidance:read']
      responses:
        "200":
          description: Guidance content
        "401":
          $ref: "#/components/responses/Unauthorized"
