openapi: 3.1.0
info:
  title: APEX Vector API
  version: 0.1.0
  summary: Verification and trust engine of the APEX Suite.
  description: |
    Vector is the APEX Suite's verification and trust engine. It verifies claims
    against evidence, scores entity risk across multiple dimensions, runs due
    diligence checks, executes asynchronous investigations, maintains
    tenant-scoped knowledge graphs, and maps regulatory compliance.

    ## Authentication

    Send `Authorization: Bearer <tenant API key>` on every request. The token is
    a platform API key issued through Forge — it is **not** a JSON Web Token.
    Keys are verified centrally against the platform key store.

    - Missing header → `401 {"error": "AUTH_REQUIRED"}`
    - Invalid key → `401 {"error": "AUTH_INVALID"}`
    - Key does not match the requested tenant → `403 {"error": "TENANT_MISMATCH"}`

    The model catalog endpoints (`/models/*`) are the only exception — they are
    served without authentication.

    ## Tenant carriage — two patterns

    Vector uses two tenant-addressing patterns. Each operation below documents
    which one it uses:

    1. **Query parameter** `tenant_id` (required) — verification core,
       investigations, federated search, compliance, and security tools.
    2. **Path segment** `/api/v1/{tenant_id}/...` — methodology assessments,
       company knowledge graphs, and the evidence graph.

    ## Response envelope

    Most routes wrap their payload in the standard APEX envelope:

    ```json
    {"ok": true, "data": {...}, "error": null,
     "meta": {"request_id": "...", "timestamp": "...", "version": "..."}}
    ```

    The verification core routes (`/verify`, `/verify/batch`, `/score-risk`,
    `/check-entity`, `/validate-data`) return their result models directly,
    without the envelope.

    ## Rate limits

    Per-tenant hourly caps apply to `/verify`, `/score-risk`, and
    `/check-entity`. Exceeding a cap returns `429` with a `Retry-After` header.

    ## Two graph systems

    Vector operates two distinct graph systems. Do not conflate them:

    - **Company knowledge graphs** (`/api/v1/{tenant_id}/company-graphs/...`) —
      entity and relationship intelligence about companies, people, and assets.
    - **Evidence graph** (`/api/v1/{tenant_id}/graph/...`) — verification
      provenance linking claims to the evidence that supported or contradicted
      them.
servers:
  - url: https://vector.dev.apex.reisiger.org
    description: Development
  - url: http://localhost:9120
    description: Local
security:
  - bearerAuth: []
tags:
  - name: Verification
    description: >-
      Claim verification, batch verification, risk scoring, entity due
      diligence, and data quality validation. Tenant is carried in the
      `tenant_id` query parameter. Results are returned directly (no envelope).
  - name: Investigations
    description: >-
      Asynchronous multi-stage investigations of an entity. Tenant is carried
      in the `tenant_id` query parameter. Responses use the standard envelope.
  - name: Assessments
    description: >-
      Methodology-pack security and governance assessments. Tenant is carried
      in the URL path (`/api/v1/{tenant_id}/...`).
  - name: Company Knowledge Graphs
    description: >-
      Tenant-scoped entity and relationship intelligence graphs — create,
      populate, verify, and export. Distinct from the evidence graph, which
      records verification provenance. Tenant is carried in the URL path.
  - name: Evidence Graph
    description: >-
      Read-only view of verification provenance — the claims Vector has
      verified, the evidence behind each verdict, and the entities they
      concern. Distinct from the company knowledge graphs, which hold
      entity/relationship intelligence. Tenant is carried in the URL path.
  - name: Search
    description: Federated search across Vector records for platform search surfaces.
  - name: Compliance
    description: >-
      South African regulatory compliance assessment, including the Protection
      of Personal Information Act, and requirement-to-proposal mapping. Tenant
      is carried in the `tenant_id` query parameter.
  - name: Models
    description: >-
      Language-model catalog served by Vector. These endpoints require no
      authentication.
  - name: Tools
    description: Security scanning tool catalog, status, and execution.
paths:
  # ---------------------------------------------------------------- Verification
  /verify:
    post:
      operationId: verifyClaim
      tags: [Verification]
      summary: Verify a claim against evidence
      description: >-
        Verifies a single claim using the configured evidence source and
        returns a verdict with a confidence score, cited evidence, and cost.
        Subject to the per-tenant hourly verification cap.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerificationRequest'
            example:
              claim: Acme Holdings reported revenue growth of 12 percent in 2025.
              context: Assessing the accuracy of statements in a supplier onboarding pack.
              evidence:
                - source: annual-report-2025.pdf
                  content: Revenue grew 12.1 percent year on year to R1.4 billion.
                  supports_claim: true
                  relevance: 0.9
                  source_credibility: 0.8
              depth: standard
              evidence_source: auto
      responses:
        '200':
          description: Verification result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
        '404':
          $ref: '#/components/responses/TenantNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
  /verify/batch:
    post:
      operationId: verifyClaimsBatch
      tags: [Verification]
      summary: Verify a batch of claims
      description: >-
        Verifies 1–100 claims in a single request and returns per-claim results
        plus aggregate verdict counts and total cost.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchVerificationRequest'
            example:
              claims:
                - claim: Acme Holdings is registered in South Africa.
                  depth: quick
                - claim: Acme Holdings holds an active water use licence.
                  depth: standard
              shared_context: Supplier onboarding review for your-tenant.
      responses:
        '200':
          description: Aggregated batch verification result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchVerificationResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
        '404':
          $ref: '#/components/responses/TenantNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
  /score-risk:
    post:
      operationId: scoreRisk
      tags: [Verification]
      summary: Score entity risk across dimensions
      description: >-
        Scores an entity across the requested risk dimensions and returns an
        overall score and level, per-dimension breakdowns, and flags. Subject
        to the per-tenant hourly risk-scoring cap.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RiskScoreRequest'
            example:
              entity_name: Acme Holdings
              entity_type: company
              dimensions: [financial, regulatory, reputational]
              context: Pre-contract risk review.
              depth: standard
      responses:
        '200':
          description: Multi-dimensional risk assessment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RiskScoreResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
        '404':
          $ref: '#/components/responses/TenantNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
  /check-entity:
    post:
      operationId: checkEntity
      tags: [Verification]
      summary: Run a full due diligence check on an entity
      description: >-
        Produces a sectioned due diligence dossier for an entity (identity,
        ownership, financials, risk, sanctions, media, legal, relationships).
        Requires a Professional-tier subscription or above — entry-tier tenants
        receive `403`. Subject to the per-tenant hourly entity-check cap.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EntityCheckRequest'
            example:
              entity_name: Acme Holdings
              entity_type: company
              jurisdiction: ZA
              sections: [identity, ownership, risk, sanctions]
              depth: standard
      responses:
        '200':
          description: Due diligence dossier.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EntityCheckResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            Subscription tier does not include entity checks, or the key does
            not match the requested tenant.
        '404':
          $ref: '#/components/responses/TenantNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
  /validate-data:
    post:
      operationId: validateData
      tags: [Verification]
      summary: Validate data quality
      description: >-
        Profiles a set of records and assesses quality across the requested
        checks (completeness, uniqueness, consistency, format, outliers).
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DataValidationRequest'
            example:
              data:
                - supplier_id: SUP-001
                  name: Acme Holdings
                  registration_number: 2001/012345/07
                - supplier_id: SUP-002
                  name: Northwind Manufacturing
                  registration_number: null
              schema_hint: supplier master records
              checks: [completeness, uniqueness, format]
      responses:
        '200':
          description: Data quality assessment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataValidationResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
        '404':
          $ref: '#/components/responses/TenantNotFound'
  # ---------------------------------------------------------------- Investigations
  /investigations:
    post:
      operationId: startInvestigation
      tags: [Investigations]
      summary: Start an investigation
      description: >-
        Starts an asynchronous multi-stage investigation of an entity. Returns
        immediately with a pending investigation identifier; poll
        `GET /investigations/{investigation_id}` for progress and results.
        Requires a Professional-tier subscription or above — entry-tier tenants
        receive `403`.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartInvestigationRequest'
            example:
              entity_name: Acme Holdings
              entity_type: company
              source: manual
              depth: standard
              sections: [identity, ownership, risk, sanctions]
              run_posture: true
              run_verification: true
              max_verification_claims: 5
      responses:
        '200':
          description: Investigation accepted and queued.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: >-
                          Pending investigation record, including the
                          investigation identifier, initial status, and the
                          processing pipeline selected for the requested depth.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            Subscription tier does not include investigations, or the key does
            not match the requested tenant.
        '404':
          $ref: '#/components/responses/TenantNotFound'
    get:
      operationId: listInvestigations
      tags: [Investigations]
      summary: List investigations
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
        - name: limit
          in: query
          description: Maximum number of investigations to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: Investigation summaries for the tenant.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          investigations:
                            type: array
                            items:
                              $ref: '#/components/schemas/InvestigationSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
        '404':
          $ref: '#/components/responses/TenantNotFound'
  /investigations/{investigation_id}:
    get:
      operationId: getInvestigation
      tags: [Investigations]
      summary: Get an investigation
      description: >-
        Returns the full investigation record — completed stage outputs for
        finished investigations, or the pending/in-progress status for active
        ones.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
        - $ref: '#/components/parameters/InvestigationIdPath'
      responses:
        '200':
          description: Full investigation record.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: >-
                          Investigation record. Stage outputs mirror the
                          verification, risk-scoring, and entity-check result
                          models.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Investigation or tenant not found.
  /investigations/{investigation_id}/graph:
    get:
      operationId: getInvestigationGraph
      tags: [Investigations]
      summary: Get the investigation graph
      description: >-
        Returns the investigation's entity graph in a Cytoscape-compatible
        nodes-and-edges format for direct rendering.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
        - $ref: '#/components/parameters/InvestigationIdPath'
      responses:
        '200':
          description: Graph data for rendering.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/InvestigationGraph'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Investigation or tenant not found.
  # ---------------------------------------------------------------- Assessments
  /api/v1/{tenant_id}/assessments:
    post:
      operationId: runAssessment
      tags: [Assessments]
      summary: Run a methodology-pack assessment
      description: >-
        Runs a methodology-pack assessment against a collector. The only
        supported collector in the current release is `microsoft_graph`; other
        collector values return `422`, as does an unknown pack. Discover valid
        packs via `GET /api/v1/{tenant_id}/methodology/packs`.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunAssessmentRequest'
            example:
              pack: identity-baseline
              target_name: primary-directory
              target_type: identity
              collector: microsoft_graph
              metadata:
                requested_by: governance-team
      responses:
        '200':
          description: Assessment report.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Assessment report for the requested pack.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant not found.
        '422':
          description: Unknown pack or unsupported collector.
    get:
      operationId: listAssessments
      tags: [Assessments]
      summary: List assessments
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      responses:
        '200':
          description: Assessment summaries for the tenant.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: List of assessment summaries.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant not found.
  /api/v1/{tenant_id}/assessments/{assessment_id}:
    get:
      operationId: getAssessment
      tags: [Assessments]
      summary: Get an assessment
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/AssessmentIdPath'
        - name: include_observations
          in: query
          description: Include the raw observation snapshot alongside the report.
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Full assessment report, optionally with observations.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Full assessment report.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or assessment not found.
  /api/v1/{tenant_id}/assessments/{assessment_id}/gaps:
    get:
      operationId: getAssessmentGaps
      tags: [Assessments]
      summary: Get assessment gaps
      description: Returns the gap register for an assessment, with optional filters.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/AssessmentIdPath'
        - name: gap_class
          in: query
          description: Filter by gap class.
          schema:
            type: string
            enum: [visibility, control, policy_reality]
        - name: dimension
          in: query
          description: Filter by assessment dimension.
          schema:
            type: string
        - name: severity
          in: query
          description: Filter by severity.
          schema:
            type: string
            enum: [critical, high, medium, low, info]
      responses:
        '200':
          description: Filtered gap register.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Gap register entries matching the filters.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or assessment not found.
  /api/v1/{tenant_id}/methodology/packs:
    get:
      operationId: listMethodologyPacks
      tags: [Assessments]
      summary: List methodology packs
      description: >-
        Lists the methodology packs available to the tenant. Each entry carries
        the pack identifier, version, reference, basis, dimensions, control
        count, and judged-control count.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      responses:
        '200':
          description: Available methodology packs.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          packs:
                            type: array
                            items:
                              $ref: '#/components/schemas/MethodologyPack'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant not found.
  # ------------------------------------------------------ Company knowledge graphs
  /api/v1/{tenant_id}/company-graphs:
    post:
      operationId: createCompanyGraph
      tags: [Company Knowledge Graphs]
      summary: Create a company knowledge graph
      description: Creates a new graph centred on a subject entity.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateGraphRequest'
            example:
              subject_name: Acme Holdings
              subject_type: company
              name: Acme Holdings ownership map
              metadata:
                purpose: supplier due diligence
      responses:
        '200':
          description: Created graph summary.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Created graph, including its graph identifier.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant not found.
    get:
      operationId: listCompanyGraphs
      tags: [Company Knowledge Graphs]
      summary: List company knowledge graphs
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      responses:
        '200':
          description: Graph summaries for the tenant.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: List of graph summaries.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}:
    get:
      operationId: getCompanyGraph
      tags: [Company Knowledge Graphs]
      summary: Get a company knowledge graph
      description: >-
        Returns the graph's entities and relationships, optionally filtered by
        entity type, relationship type, minimum confidence, and traversal
        depth.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
        - name: entity_type
          in: query
          description: Filter entities by type.
          schema:
            $ref: '#/components/schemas/CompanyEntityType'
        - name: relationship_type
          in: query
          description: Filter relationships by type.
          schema:
            $ref: '#/components/schemas/RelationshipType'
        - name: min_confidence
          in: query
          description: Only include relationships at or above this confidence.
          schema:
            type: number
            minimum: 0
            maximum: 1
        - name: max_hops
          in: query
          description: Maximum traversal depth from the subject entity.
          schema:
            type: integer
            minimum: 1
            maximum: 6
      responses:
        '200':
          description: Graph contents.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entities:
                            type: array
                            items:
                              $ref: '#/components/schemas/GraphEntitySummary'
                          relationships:
                            type: array
                            items:
                              $ref: '#/components/schemas/GraphRelationshipSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/entities:
    post:
      operationId: addGraphEntity
      tags: [Company Knowledge Graphs]
      summary: Add an entity to a graph
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddEntityRequest'
            example:
              name: Jane Dlamini
              entity_type: person
              aliases: [J. Dlamini]
              metadata:
                role: director
      responses:
        '200':
          description: Added entity.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/GraphEntitySummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/relationships:
    post:
      operationId: assertGraphRelationship
      tags: [Company Knowledge Graphs]
      summary: Assert a relationship
      description: >-
        Asserts an analyst-entered relationship between two entities. Endpoints
        may be given by entity identifier (must already exist) or by name
        (upserted automatically). Asserted edges start at confidence `0.0` and
        remain flagged as unverified until they pass the verification pipeline.
        Missing endpoint identifier or name returns `422`.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddRelationshipRequest'
            example:
              source_name: Jane Dlamini
              source_type: person
              target_name: Acme Holdings
              target_type: company
              relationship_type: director_of
              claim: Jane Dlamini serves as a director of Acme Holdings.
      responses:
        '200':
          description: Asserted relationship (confidence 0.0 until verified).
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/GraphRelationshipSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
        '422':
          description: Relationship endpoints missing — provide an entity identifier or name for both ends.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/entities/{entity_id}:
    get:
      operationId: getGraphEntityDossier
      tags: [Company Knowledge Graphs]
      summary: Get an entity dossier
      description: >-
        Returns the full dossier for one entity in the graph — attributes,
        relationships, and provenance.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
        - name: entity_id
          in: path
          required: true
          description: Entity identifier (may contain path separators).
          schema:
            type: string
      responses:
        '200':
          description: Entity dossier.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Entity dossier.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant, graph, or entity not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/ingest:
    post:
      operationId: ingestGraphSources
      tags: [Company Knowledge Graphs]
      summary: Ingest entities and relationships from a source
      description: >-
        Populates the graph from a connected source. Supported sources:
        `zenith` (document extraction), `zenith_kg` (knowledge-graph bridge),
        `spectra` (structural bridge), and `registry` (external registry
        adapters — the current adapter is `opensanctions`). An unknown source
        returns `422`.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IngestRequest'
            example:
              source: zenith
              query: Acme Holdings
              max_chunks: 10
      responses:
        '200':
          description: Ingest summary — entities and relationships added.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Ingest run summary.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
        '422':
          description: Unknown ingest source.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/relationships/{relationship_id}/verify:
    post:
      operationId: verifyGraphRelationship
      tags: [Company Knowledge Graphs]
      summary: Verify one relationship
      description: >-
        Runs the verification pipeline against a single relationship's claim
        and updates its confidence and verification record.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
        - name: relationship_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Updated relationship with verification outcome.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/GraphRelationshipSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant, graph, or relationship not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/verify:
    post:
      operationId: verifyGraphRelationshipsBatch
      tags: [Company Knowledge Graphs]
      summary: Verify relationships in batch
      description: >-
        Verifies up to 25 of the graph's lowest-confidence relationships in one
        run.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchVerifyRequest'
            example:
              max_confidence: 0.7
              limit: 10
              include_verified: false
      responses:
        '200':
          description: Batch verification summary with per-relationship outcomes.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Batch verification run summary.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/gaps:
    get:
      operationId: getCompanyGraphGaps
      tags: [Company Knowledge Graphs]
      summary: Get the graph gap register
      description: >-
        Lists knowledge gaps in the graph — unverified edges, missing expected
        relationships, and thin coverage areas.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      responses:
        '200':
          description: Gap register.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Gap register entries.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/risk:
    post:
      operationId: rollupCompanyGraphRisk
      tags: [Company Knowledge Graphs]
      summary: Roll up risk across the graph
      description: >-
        Scores risk for up to 10 of the graph's entities and rolls the results
        up to the subject. An unknown risk dimension returns `422`.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RiskRollupRequest'
            example:
              max_entities: 5
              dimensions: [financial, regulatory]
      responses:
        '200':
          description: Graph risk rollup.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Per-entity risk scores and the rolled-up view.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
        '422':
          description: Unknown risk dimension.
  /api/v1/{tenant_id}/company-graphs/{graph_id}/export:
    get:
      operationId: exportCompanyGraph
      tags: [Company Knowledge Graphs]
      summary: Export a graph
      description: Exports the full graph as JSON or GraphML.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - $ref: '#/components/parameters/GraphIdPath'
        - name: format
          in: query
          description: Export format.
          schema:
            type: string
            enum: [json, graphml]
            default: json
      responses:
        '200':
          description: Graph export in the requested format.
          content:
            application/json:
              schema:
                type: object
                description: Full graph export (when `format=json`).
            application/xml:
              schema:
                type: string
                description: GraphML document (when `format=graphml`).
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Tenant or graph not found.
  # ---------------------------------------------------------------- Evidence graph
  /api/v1/{tenant_id}/graph/stats:
    get:
      operationId: getEvidenceGraphStats
      tags: [Evidence Graph]
      summary: Get evidence graph statistics
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
      responses:
        '200':
          description: Node and edge counts for the tenant's evidence graph.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          tenant_id:
                            type: string
                          stats:
                            type: object
                            description: Graph statistics.
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/{tenant_id}/graph/entities:
    get:
      operationId: listEvidenceGraphEntities
      tags: [Evidence Graph]
      summary: List entities in the evidence graph
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Entities that appear in verification provenance.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entities:
                            type: array
                            items:
                              type: object
                              properties:
                                node_id:
                                  type: string
                                name:
                                  type: string
                                entity_type:
                                  type: string
                                aliases:
                                  type: array
                                  items:
                                    type: string
                                investigation_count:
                                  type: integer
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/{tenant_id}/graph/claims:
    get:
      operationId: listEvidenceGraphClaims
      tags: [Evidence Graph]
      summary: List verified claims
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: entity
          in: query
          description: Filter claims by entity name.
          schema:
            type: string
        - name: verdict
          in: query
          description: Filter by verdict.
          schema:
            type: string
            enum: [supported, contradicted, insufficient, mixed]
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Claims recorded in the evidence graph.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          claims:
                            type: array
                            items:
                              type: object
                              properties:
                                node_id:
                                  type: string
                                text:
                                  type: string
                                entity_name:
                                  type: string
                                verdict:
                                  type: string
                                confidence:
                                  type: number
                                investigation_id:
                                  type: string
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/{tenant_id}/graph/evidence:
    get:
      operationId: queryEvidenceForClaim
      tags: [Evidence Graph]
      summary: Find evidence for a claim
      description: Finds related evidence for a claim using graph traversal.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: claim
          in: query
          required: true
          description: Claim text to find evidence for.
          schema:
            type: string
        - name: entity
          in: query
          description: Restrict to evidence about this entity.
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
      responses:
        '200':
          description: Evidence items related to the claim.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          claim:
                            type: string
                          evidence:
                            type: array
                            items:
                              $ref: '#/components/schemas/Evidence'
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/{tenant_id}/graph/chain/{claim_id}:
    get:
      operationId: getEvidenceChain
      tags: [Evidence Graph]
      summary: Trace an evidence chain
      description: Traces the full evidence chain behind a specific claim.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: claim_id
          in: path
          required: true
          schema:
            type: string
        - name: depth
          in: query
          description: Maximum traversal depth.
          schema:
            type: integer
            minimum: 1
            maximum: 5
            default: 3
      responses:
        '200':
          description: Evidence chain for the claim.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Claim node plus the linked evidence chain.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Claim not found in the graph.
  /api/v1/{tenant_id}/graph/related:
    get:
      operationId: getRelatedEntities
      tags: [Evidence Graph]
      summary: Find related entities
      description: Finds entities related to a given entity via graph traversal.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: entity
          in: query
          required: true
          description: Entity name to find relations for.
          schema:
            type: string
        - name: depth
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 4
            default: 2
      responses:
        '200':
          description: Related entities.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entity:
                            type: string
                          related:
                            type: array
                            items:
                              type: object
                              properties:
                                node_id:
                                  type: string
                                name:
                                  type: string
                                entity_type:
                                  type: string
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/v1/{tenant_id}/graph/contradictions:
    get:
      operationId: getContradictions
      tags: [Evidence Graph]
      summary: Find contradicted claims for an entity
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdPath'
        - name: entity
          in: query
          required: true
          description: Entity name to check.
          schema:
            type: string
      responses:
        '200':
          description: Claims with contradicting evidence.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entity:
                            type: string
                          contradictions:
                            type: array
                            items:
                              type: object
                              properties:
                                node_id:
                                  type: string
                                text:
                                  type: string
                                verdict:
                                  type: string
                                confidence:
                                  type: number
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  # ---------------------------------------------------------------- Search
  /api/search:
    post:
      operationId: federatedSearch
      tags: [Search]
      summary: Federated search across Vector records
      description: >-
        Searches entity records, verification history, and investigations, and
        returns results ranked by relevance. Designed for platform search
        surfaces with a 2000 millisecond response budget. An unknown tenant
        returns an empty successful result rather than an error.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchRequest'
            example:
              query: Acme Holdings
              entity_types: [entity, verification, investigation]
              limit: 10
      responses:
        '200':
          description: Ranked search results.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/SearchResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
  # ---------------------------------------------------------------- Compliance
  /compliance/frameworks:
    get:
      operationId: listComplianceFrameworks
      tags: [Compliance]
      summary: List compliance frameworks
      description: Lists the available regulatory frameworks with metadata.
      x-apex-availability: available
      responses:
        '200':
          description: Framework catalog.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          frameworks:
                            type: array
                            items:
                              type: object
                              description: Framework metadata.
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /compliance/check:
    post:
      operationId: runComplianceCheck
      tags: [Compliance]
      summary: Run a compliance assessment
      description: >-
        Assesses an entity against applicable South African regulatory
        frameworks. If no frameworks are specified, they are selected
        automatically from the industry. Returns per-check status with section
        references and remediation guidance.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ComplianceCheckRequest'
            example:
              entity_name: Acme Holdings
              industry: agriculture
              frameworks: [popia]
              context:
                processes_personal_information: true
      responses:
        '200':
          description: Compliance assessment result.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: >-
                          Per-framework check results with overall score,
                          section references, and remediation guidance.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
  /compliance/popia:
    post:
      operationId: runPopiaCheck
      tags: [Compliance]
      summary: Run a Protection of Personal Information Act assessment
      description: >-
        Runs an assessment specific to South Africa's Protection of Personal
        Information Act — lawful processing conditions, data subject rights,
        cross-border transfers, special personal information, and information
        regulator reporting.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PopiaCheckRequest'
            example:
              entity_name: Acme Holdings
              context:
                stores_customer_data: true
                cross_border_transfers: false
      responses:
        '200':
          description: Act-specific assessment result.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Assessment with overall status and score.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TenantMismatch'
  /compliance/pia-template:
    get:
      operationId: getPiaTemplate
      tags: [Compliance]
      summary: Generate a Privacy Impact Assessment template
      description: >-
        Generates a structured Privacy Impact Assessment template for an entity,
        suitable for downstream document rendering.
      x-apex-availability: available
      parameters:
        - name: entity_name
          in: query
          required: true
          description: Entity name for the assessment.
          schema:
            type: string
      responses:
        '200':
          description: Structured template.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Privacy Impact Assessment template.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
  /compliance/matrix:
    post:
      operationId: generateComplianceMatrix
      tags: [Compliance]
      summary: Generate a requirement-to-proposal compliance matrix
      description: >-
        Maps a list of requirements to the best-matching proposal sections,
        assesses coverage semantically, and flags gaps.
      x-apex-availability: available
      parameters:
        - $ref: '#/components/parameters/TenantIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ComplianceMatrixRequest'
            example:
              requirements:
                - id: REQ-001
                  text: The supplier must hold a valid quality management certification.
                - id: REQ-002
                  text: The supplier must provide 24-hour support coverage.
              proposal_sections:
                - id: SEC-3
                  content: Our operations hold current quality management certification, renewed annually.
                - id: SEC-7
                  content: Support is available during business hours with an on-call escalation path.
      responses:
        '200':
          description: Compliance matrix with mappings, coverage, and gaps.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/ComplianceMatrixResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/TenantNotFound'
  # ---------------------------------------------------------------- Models
  /models/providers:
    get:
      operationId: listModelProviders
      tags: [Models]
      summary: List language-model providers
      description: Lists the model providers Vector can dispatch to. No authentication required.
      x-apex-availability: available
      security: []
      responses:
        '200':
          description: Provider list.
          content:
            application/json:
              schema:
                type: object
                description: Provider catalog.
                x-apex-note: Schema partially documented — verify against the service.
  /models:
    get:
      operationId: listModels
      tags: [Models]
      summary: List available models
      description: Lists the language models available to Vector flows. No authentication required.
      x-apex-availability: available
      security: []
      responses:
        '200':
          description: Model list.
          content:
            application/json:
              schema:
                type: object
                description: Model list.
                x-apex-note: Schema partially documented — verify against the service.
  /models/catalog:
    get:
      operationId: getModelCatalog
      tags: [Models]
      summary: Get the full model catalog
      description: Returns the full model catalog with capability metadata. No authentication required.
      x-apex-availability: available
      security: []
      responses:
        '200':
          description: Full catalog.
          content:
            application/json:
              schema:
                type: object
                description: Model catalog.
                x-apex-note: Schema partially documented — verify against the service.
  # ---------------------------------------------------------------- Tools
  /api/tools/available:
    get:
      operationId: listAvailableTools
      tags: [Tools]
      summary: List security scanning tools
      description: >-
        Lists the security scanning tools Vector can run, with capability
        descriptions and whether each tool is installed on the service host.
      x-apex-availability: available
      responses:
        '200':
          description: Tool catalog.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          tools:
                            type: array
                            items:
                              type: object
                              description: Tool descriptor with an `installed` flag.
                          total:
                            type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/tools/status:
    get:
      operationId: getToolStatus
      tags: [Tools]
      summary: Get tool status for a tenant
      description: >-
        Reports which tools are installed, which are enabled for the tenant,
        and which would run in mock mode.
      x-apex-availability: available
      parameters:
        - name: tenant_id
          in: query
          required: false
          description: Tenant to check enabled tools for.
          schema:
            type: string
      responses:
        '200':
          description: Per-tool status.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          tools:
                            type: array
                            items:
                              type: object
                              properties:
                                id:
                                  type: string
                                name:
                                  type: string
                                installed:
                                  type: boolean
                                enabled:
                                  type: boolean
                                mode:
                                  type: string
                                  enum: [live, mock]
                          installed_count:
                            type: integer
                          mock_count:
                            type: integer
                          tenant_id:
                            type: [string, 'null']
        '401':
          $ref: '#/components/responses/Unauthorized'
  /api/tools/scan:
    post:
      operationId: runToolScan
      tags: [Tools]
      summary: Run security tool scans
      description: >-
        Runs one or more security tools against a target. If no tools are
        specified, all tools enabled in the tenant's configuration run. Tools
        that are not installed return mock findings. The tenant is carried in
        the request body for this operation.
      x-apex-availability: available
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ToolScanRequest'
            example:
              tenant_id: your-tenant
              tools: [trivy]
              target_name: billing-service
              target_type: infrastructure
              scan_target: registry.example.com/billing-service:latest
              scan_type: image
      responses:
        '200':
          description: Scan findings per tool.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        type: object
                        description: Findings grouped by tool.
                        x-apex-note: Schema partially documented — verify against the service.
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Forge-issued platform API key sent as a Bearer token. This is an opaque
        key, not a JSON Web Token; it is verified against the central platform
        key store.
  parameters:
    TenantIdQuery:
      name: tenant_id
      in: query
      required: true
      description: Tenant identifier.
      schema:
        type: string
      example: your-tenant
    TenantIdPath:
      name: tenant_id
      in: path
      required: true
      description: Tenant identifier.
      schema:
        type: string
      example: your-tenant
    GraphIdPath:
      name: graph_id
      in: path
      required: true
      description: Company knowledge graph identifier.
      schema:
        type: string
    AssessmentIdPath:
      name: assessment_id
      in: path
      required: true
      description: Assessment identifier.
      schema:
        type: string
    InvestigationIdPath:
      name: investigation_id
      in: path
      required: true
      description: Investigation identifier.
      schema:
        type: string
  responses:
    Unauthorized:
      description: Authentication missing or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuthError'
          examples:
            missing:
              summary: No Authorization header
              value:
                error: AUTH_REQUIRED
            invalid:
              summary: Key not recognised
              value:
                error: AUTH_INVALID
    TenantMismatch:
      description: The authenticated key does not match the requested tenant.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuthError'
          example:
            error: TENANT_MISMATCH
    TenantNotFound:
      description: Tenant not found.
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Envelope'
            description: Error envelope with code `TENANT_NOT_FOUND`.
    RateLimited:
      description: Per-tenant hourly cap exceeded for this operation.
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
  schemas:
    Envelope:
      type: object
      description: Standard APEX response envelope.
      properties:
        ok:
          type: boolean
        data:
          description: Operation payload. Present on success.
        error:
          oneOf:
            - type: 'null'
            - type: object
              properties:
                code:
                  type: string
                message:
                  type: string
                detail:
                  description: Optional structured detail.
        meta:
          type: object
          properties:
            request_id:
              type: string
            timestamp:
              type: string
              format: date-time
            version:
              type: string
    AuthError:
      type: object
      description: Plain authentication error body (not enveloped).
      properties:
        error:
          type: string
          enum: [AUTH_REQUIRED, AUTH_INVALID, TENANT_MISMATCH]
    Evidence:
      type: object
      description: A piece of evidence supporting or contradicting a claim.
      required: [source, content]
      properties:
        source:
          type: string
        content:
          type: string
        relevance:
          type: number
          minimum: 0
          maximum: 1
          default: 0
        supports_claim:
          type: boolean
          default: true
        source_credibility:
          type: number
          minimum: 0
          maximum: 1
          default: 0.5
    VerificationRequest:
      type: object
      required: [claim]
      properties:
        claim:
          type: string
          description: The claim to verify.
        context:
          type: string
          default: ''
        evidence:
          type: array
          description: Caller-supplied evidence. May be empty when using an automatic evidence source.
          items:
            $ref: '#/components/schemas/Evidence'
        depth:
          type: string
          enum: [quick, standard, comprehensive]
          default: standard
        evidence_source:
          type: string
          enum: [auto, zenith, web, graph]
          default: auto
          description: Where Vector gathers evidence when none is supplied.
        upstream_trace_id:
          type: [string, 'null']
          description: >-
            Optional upstream trace identifier for cross-product observability.
    VerificationResult:
      type: object
      description: Result of a claim verification.
      properties:
        verification_id:
          type: string
        claim:
          type: string
        verdict:
          type: string
          enum: [supported, contradicted, insufficient, mixed]
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: The single confidence number consumers should read.
        supporting_evidence:
          type: array
          items:
            $ref: '#/components/schemas/Evidence'
        contradicting_evidence:
          type: array
          items:
            $ref: '#/components/schemas/Evidence'
        reasoning:
          type: string
        model_used:
          type: string
        cost_zar:
          type: number
          description: Cost of the verification in South African rand.
        verified_at:
          type: string
          format: date-time
        hhem_score:
          type: [number, 'null']
          description: Hallucination evaluation model score, when the ensemble ran.
        ensemble_score:
          type: [number, 'null']
        hallucination_flagged:
          type: boolean
          description: >-
            True when the result should be routed to human review — either the
            hallucination evaluator flagged it or cited evidence scored below
            the tenant's grounding threshold.
        hhem_fallback:
          type: boolean
        parse_status:
          type: string
          enum: [ok, parse_failed]
          description: >-
            Integrity signal. `parse_failed` means the model response could not
            be consumed cleanly — confidence is zeroed and the spend is recorded
            in `wasted_cost_zar` instead of `cost_zar`.
        evidence_indices_used:
          type: object
          description: Indices of the supplied evidence the model actually cited, for grounding audits.
          properties:
            supporting:
              type: array
              items:
                type: integer
            contradicting:
              type: array
              items:
                type: integer
        grounding_scores:
          type: object
          description: >-
            Lexical grounding score per cited evidence item, in the range 0–1.
            A value of -1.0 marks a claim too short to score.
          properties:
            supporting:
              type: array
              items:
                type: number
            contradicting:
              type: array
              items:
                type: number
        min_grounding_score:
          type: number
        wasted_cost_zar:
          type: number
          description: Spend on a failed parse, excluded from `cost_zar`.
        parse_retries:
          type: integer
          description: Extra model calls made before success or giving up.
        confidence_breakdown:
          type: object
          deprecated: true
          description: >-
            Deprecated mirror of `confidence` kept for one release. Read
            `confidence` instead.
    BatchVerificationRequest:
      type: object
      required: [claims]
      properties:
        claims:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/VerificationRequest'
        shared_context:
          type: string
          default: ''
          description: Context applied to every claim in the batch.
    BatchVerificationResult:
      type: object
      properties:
        results:
          type: array
          items:
            $ref: '#/components/schemas/VerificationResult'
        total_claims:
          type: integer
        supported:
          type: integer
        contradicted:
          type: integer
        insufficient:
          type: integer
        mixed:
          type: integer
        aggregate_gates_score:
          type: number
          description: Aggregate confidence across the batch.
        total_cost_zar:
          type: number
        degraded_claims:
          type: integer
          description: >-
            Number of claims whose model response failed to parse. If greater
            than zero the aggregate score is degraded.
        wasted_cost_zar:
          type: number
    GatesScore:
      type: object
      description: >-
        Five-dimension confidence breakdown — evidence gathering, source
        assessment, cross-reference testing, domain evaluation, and the final
        score.
      properties:
        gather:
          type: number
          minimum: 0
          maximum: 1
        assess:
          type: number
          minimum: 0
          maximum: 1
        test:
          type: number
          minimum: 0
          maximum: 1
        evaluate:
          type: number
          minimum: 0
          maximum: 1
        score:
          type: number
          minimum: 0
          maximum: 1
    RiskScoreRequest:
      type: object
      required: [entity_name]
      properties:
        entity_name:
          type: string
        entity_type:
          type: string
          enum: [company, person, project, country, sector]
          default: company
        dimensions:
          type: array
          description: Risk dimensions to score. Defaults to all six.
          items:
            type: string
            enum: [financial, reputational, regulatory, operational, political, environmental]
        context:
          type: string
          default: ''
        depth:
          type: string
          enum: [quick, standard, comprehensive]
          default: standard
    RiskScoreResult:
      type: object
      properties:
        risk_id:
          type: string
        entity_name:
          type: string
        entity_type:
          type: string
          enum: [company, person, project, country, sector]
        overall_score:
          type: number
          minimum: 0
          maximum: 1
        overall_level:
          type: string
          enum: [critical, high, medium, low, minimal]
        dimensions:
          type: array
          items:
            type: object
            properties:
              dimension:
                type: string
                enum: [financial, reputational, regulatory, operational, political, environmental]
              score:
                type: number
                minimum: 0
                maximum: 1
              level:
                type: string
                enum: [critical, high, medium, low, minimal]
              factors:
                type: array
                items:
                  type: string
        flags:
          type: array
          items:
            type: string
        confidence:
          $ref: '#/components/schemas/GatesScore'
        model_used:
          type: string
        cost_zar:
          type: number
        scored_at:
          type: string
          format: date-time
        parse_status:
          type: string
          enum: [ok, parse_failed]
        wasted_cost_zar:
          type: number
    EntityCheckRequest:
      type: object
      required: [entity_name]
      properties:
        entity_name:
          type: string
        entity_type:
          type: string
          enum: [company, person, project, country, sector]
          default: company
        jurisdiction:
          type: string
          default: ZA
        sections:
          type: array
          description: Dossier sections to produce. Defaults to all eight.
          items:
            type: string
            enum: [identity, ownership, financials, risk, sanctions, media, legal, relationships]
        depth:
          type: string
          enum: [quick, standard, comprehensive]
          default: standard
    EntityCheckResult:
      type: object
      description: Full due diligence dossier.
      properties:
        check_id:
          type: string
        entity_name:
          type: string
        entity_type:
          type: string
        jurisdiction:
          type: string
        sections:
          type: array
          items:
            type: object
            properties:
              title:
                type: string
              content:
                type: string
              confidence:
                type: number
                minimum: 0
                maximum: 1
              sources:
                type: array
                items:
                  type: string
        risk:
          oneOf:
            - $ref: '#/components/schemas/RiskScoreResult'
            - type: 'null'
        confidence:
          $ref: '#/components/schemas/GatesScore'
        model_used:
          type: string
        cost_zar:
          type: number
        checked_at:
          type: string
          format: date-time
        parse_status:
          type: string
          enum: [ok, parse_failed]
        wasted_cost_zar:
          type: number
    DataValidationRequest:
      type: object
      properties:
        data:
          type: array
          description: Records to profile.
          items:
            type: object
        schema_hint:
          type: string
          default: ''
          description: Free-text hint about the expected structure.
        checks:
          type: array
          description: Checks to run. Defaults to all five.
          items:
            type: string
            enum: [completeness, uniqueness, consistency, format, outliers]
    DataValidationResult:
      type: object
      properties:
        validation_id:
          type: string
        quality_level:
          type: string
          enum: [excellent, good, fair, poor, unusable]
        overall_score:
          type: number
          minimum: 0
          maximum: 1
        profile:
          type: object
          properties:
            total_records:
              type: integer
            total_fields:
              type: integer
            completeness:
              type: number
              minimum: 0
              maximum: 1
            uniqueness:
              type: number
              minimum: 0
              maximum: 1
            consistency:
              type: number
              minimum: 0
              maximum: 1
            field_profiles:
              type: object
              description: Per-field statistics.
        issues:
          type: array
          items:
            type: object
        recommendations:
          type: array
          items:
            type: string
        validated_at:
          type: string
          format: date-time
    StartInvestigationRequest:
      type: object
      required: [entity_name]
      properties:
        entity_name:
          type: string
        entity_type:
          type: string
          enum: [company, person, project, country, sector]
          default: company
        source:
          type: string
          enum: [github, manual, upload]
          default: manual
          description: Where investigation data comes from.
        depth:
          type: string
          enum: [quick, standard, comprehensive]
          default: standard
        sections:
          type: array
          description: Dossier sections to produce. Defaults to all eight.
          items:
            type: string
            enum: [identity, ownership, financials, risk, sanctions, media, legal, relationships]
        run_posture:
          type: boolean
          default: true
          description: Run the security posture stage.
        run_verification:
          type: boolean
          default: true
          description: Verify key claims extracted from the entity check.
        run_github_discovery:
          type: boolean
          default: false
          description: Discover the entity's public code repositories.
        run_github_profiling:
          type: boolean
          default: false
          description: Profile discovered repositories for technology stack and findings.
        run_tool_scanning:
          type: boolean
          default: false
          description: Run enabled security scanning tools.
        max_verification_claims:
          type: integer
          minimum: 1
          maximum: 20
          default: 5
        max_repos_to_scan:
          type: integer
          minimum: 1
          maximum: 50
          default: 10
    InvestigationSummary:
      type: object
      properties:
        investigation_id:
          type: string
        entity_name:
          type: string
        entity_type:
          type: string
        status:
          type: string
          enum: [pending, in_progress, complete, failed]
        stages_completed:
          type: array
          items:
            type: string
        stages_failed:
          type: array
          items:
            type: string
        created_at:
          type: string
        completed_at:
          type: [string, 'null']
    InvestigationGraph:
      type: object
      description: Nodes-and-edges graph in a Cytoscape-compatible shape.
      properties:
        investigation_id:
          type: string
        entity:
          type: string
        nodes:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              label:
                type: string
              type:
                type: string
              group:
                type: string
        edges:
          type: array
          items:
            type: object
            properties:
              source:
                type: string
              target:
                type: string
              type:
                type: string
        node_count:
          type: integer
        edge_count:
          type: integer
    RunAssessmentRequest:
      type: object
      required: [pack]
      properties:
        pack:
          type: string
          description: >-
            Methodology pack identifier. Discover valid packs via
            `GET /api/v1/{tenant_id}/methodology/packs`.
        target_name:
          type: string
          default: ''
        target_type:
          type: string
          default: identity
        collector:
          type: string
          default: microsoft_graph
          description: Observation collector. Only `microsoft_graph` is supported in the current release.
        metadata:
          type: object
          additionalProperties: true
    MethodologyPack:
      type: object
      properties:
        pack:
          type: string
        version:
          type: string
        ref:
          type: string
        basis:
          type: string
        dimensions:
          type: array
          items:
            type: string
        control_count:
          type: integer
        judged_count:
          type: integer
    CompanyEntityType:
      type: string
      description: Node types for company knowledge graphs.
      enum: [company, person, project, country, sector, regulator, asset, financial_instrument]
    RelationshipType:
      type: string
      description: Controlled edge vocabulary for company knowledge graphs.
      enum:
        - shareholder_of
        - director_of
        - officer_of
        - subsidiary_of
        - supplier_to
        - customer_of
        - regulated_by
        - party_to
        - sanctioned_by
        - related_party
        - located_in
    CreateGraphRequest:
      type: object
      required: [subject_name]
      properties:
        subject_name:
          type: string
          description: The entity the graph is centred on.
        subject_type:
          $ref: '#/components/schemas/CompanyEntityType'
        name:
          type: string
          default: ''
          description: Display name for the graph.
        metadata:
          type: object
          additionalProperties: true
    AddEntityRequest:
      type: object
      required: [name]
      properties:
        name:
          type: string
        entity_type:
          $ref: '#/components/schemas/CompanyEntityType'
        aliases:
          type: array
          items:
            type: string
        attributes:
          type: array
          description: Typed entity attributes.
          items:
            type: object
            x-apex-note: Schema partially documented — verify against the service.
        metadata:
          type: object
          additionalProperties: true
    AddRelationshipRequest:
      type: object
      required: [relationship_type, claim]
      description: >-
        Relationship endpoints may be given by identifier (`source_entity_id` /
        `target_entity_id`, must already exist) or by name (`source_name` /
        `target_name`, upserted automatically).
      properties:
        source_entity_id:
          type: string
          default: ''
        target_entity_id:
          type: string
          default: ''
        source_name:
          type: string
          default: ''
        source_type:
          $ref: '#/components/schemas/CompanyEntityType'
        target_name:
          type: string
          default: ''
        target_type:
          $ref: '#/components/schemas/CompanyEntityType'
        relationship_type:
          $ref: '#/components/schemas/RelationshipType'
        claim:
          type: string
          description: The claim this relationship represents.
        evidence:
          type: array
          items:
            $ref: '#/components/schemas/Evidence'
        confidence:
          type: number
          minimum: 0
          maximum: 1
          default: 0
          description: >-
            Asserted relationships are stored at confidence 0.0 regardless of
            this value until they pass verification.
        valid_from:
          type: [string, 'null']
          format: date-time
        valid_to:
          type: [string, 'null']
          format: date-time
        metadata:
          type: object
          additionalProperties: true
    IngestRequest:
      type: object
      properties:
        source:
          type: string
          enum: [zenith, zenith_kg, spectra, registry]
          default: zenith
        query:
          type: [string, 'null']
          description: Search query. Defaults to the graph's subject entity name.
        max_chunks:
          type: integer
          minimum: 1
          maximum: 50
          default: 10
          description: Maximum document chunks to extract from (document sources).
        limit:
          type: integer
          minimum: 1
          maximum: 1000
          default: 200
          description: Maximum triples to import (bridge sources).
        adapter:
          type: string
          default: opensanctions
          description: Registry adapter to use when `source` is `registry`.
    BatchVerifyRequest:
      type: object
      properties:
        max_confidence:
          type: number
          minimum: 0
          maximum: 1
          default: 0.7
          description: Only verify relationships at or below this confidence.
        limit:
          type: integer
          minimum: 1
          maximum: 25
          default: 10
        include_verified:
          type: boolean
          default: false
    RiskRollupRequest:
      type: object
      properties:
        max_entities:
          type: integer
          minimum: 1
          maximum: 10
          default: 5
        dimensions:
          type: array
          description: Risk dimensions to score. Empty means all.
          items:
            type: string
    GraphEntitySummary:
      type: object
      properties:
        entity_id:
          type: string
        name:
          type: string
        entity_type:
          type: string
        aliases:
          type: array
          items:
            type: string
        attribute_count:
          type: integer
        source_systems:
          type: array
          description: Provenance systems that contributed this entity.
          items:
            type: string
            enum: [vector_manual, vector_extraction, vector_verify, vector_registry, zenith_kg, spectra]
    GraphRelationshipSummary:
      type: object
      properties:
        relationship_id:
          type: string
        source_entity_id:
          type: string
        target_entity_id:
          type: string
        relationship_type:
          $ref: '#/components/schemas/RelationshipType'
        claim:
          type: string
        confidence:
          type: number
        asserted:
          type: boolean
          description: True when analyst-entered and not yet verified.
        verified:
          type: boolean
        evidence_count:
          type: integer
        source_system:
          type: string
          enum: [vector_manual, vector_extraction, vector_verify, vector_registry, zenith_kg, spectra]
        valid_from:
          type: [string, 'null']
        valid_to:
          type: [string, 'null']
    SearchRequest:
      type: object
      required: [query]
      properties:
        query:
          type: string
        entity_types:
          type: array
          description: Record types to search.
          items:
            type: string
            enum: [entity, verification, investigation]
          default: [entity, verification, investigation]
        limit:
          type: integer
          minimum: 1
          maximum: 50
          default: 10
    SearchResponse:
      type: object
      properties:
        query:
          type: string
        total:
          type: integer
        results:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              type:
                type: string
                enum: [entity, verification, investigation]
              title:
                type: string
              description:
                type: string
              score:
                type: number
              url:
                type: string
              metadata:
                type: object
        searched_types:
          type: array
          items:
            type: string
    ComplianceCheckRequest:
      type: object
      required: [entity_name]
      properties:
        entity_name:
          type: string
        industry:
          type: string
          default: general
          description: Used to auto-select frameworks when none are given.
        frameworks:
          type: array
          description: Framework identifiers. Discover via `GET /compliance/frameworks`.
          items:
            type: string
        context:
          type: object
          additionalProperties: true
    PopiaCheckRequest:
      type: object
      required: [entity_name]
      properties:
        entity_name:
          type: string
        context:
          type: object
          additionalProperties: true
    ComplianceMatrixRequest:
      type: object
      required: [requirements, proposal_sections]
      properties:
        requirements:
          type: array
          description: Each requirement needs at least `id` and `text` fields.
          items:
            type: object
            properties:
              id:
                type: string
              text:
                type: string
        proposal_sections:
          type: array
          description: Each section needs at least `id` and `content` fields.
          items:
            type: object
            properties:
              id:
                type: string
              content:
                type: string
        frameworks:
          type: array
          items:
            type: string
    ComplianceMatrixResult:
      type: object
      properties:
        mappings:
          type: array
          description: Best-match mapping per covered requirement.
          items:
            type: object
            properties:
              requirement_id:
                type: string
              requirement_text:
                type: string
              section_id:
                type: string
              coverage_score:
                type: number
              verdict:
                type: string
              reasoning:
                type: string
        coverage_percentage:
          type: number
        gaps:
          type: array
          items:
            type: object
            properties:
              requirement_id:
                type: string
              requirement_text:
                type: string
              reason:
                type: string
              best_score:
                type: number
        total_requirements:
          type: integer
        mapped_requirements:
          type: integer
        cost_zar:
          type: number
    ToolScanRequest:
      type: object
      required: [tenant_id]
      properties:
        tenant_id:
          type: string
          description: Tenant identifier (carried in the body for this operation).
        tools:
          type: array
          description: Tool identifiers to run. Empty runs all tools enabled for the tenant.
          items:
            type: string
        target_name:
          type: string
          default: default
        target_type:
          type: string
          default: infrastructure
        urls:
          type: array
          description: Target addresses for web scanning tools.
          items:
            type: string
        repo_path:
          type: string
          default: ''
          description: Repository path for static analysis tools.
        scan_target:
          type: string
          default: ''
          description: Image reference or path for container and filesystem scanning.
        scan_type:
          type: string
          enum: [image, fs, config, repo]
          default: fs
        model_name:
          type: string
          default: ''
          description: Language-model name for model probing tools.
        model_type:
          type: string
          default: openai
          description: Language-model provider type for model probing tools.
