openapi: 3.1.0
info:
  title: NoData Public Verification API
  version: 1.0.0
  description: |
    Public verification surface for NoData receipts, signed folders, audit chain
    segments, and audit-export bundles. All endpoints are publicly callable
    (no auth), IP-rate-limited, and return JSON. This is the "anyone can verify"
    layer of the NoData control plane.

    For the closed-source server endpoints (key wrapping, tenant management,
    chain append) you need an API key — see /pricing.
  contact:
    name: NoData security
    email: security@nodatacapsule.com
  license:
    name: Public verification endpoints — no usage license required for verification

servers:
  - url: https://www.nodatacapsule.com/api
    description: Production

paths:
  /verify:
    post:
      summary: Verify a single signed file's receipt
      description: |
        Given a content_hash (SHA-256) and a receipt sidecar (or receipt_id),
        re-derives the chain HMAC server-side and reports whether the
        receipt is authentic and unmodified.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [content_hash]
              properties:
                content_hash:
                  type: string
                  pattern: '^[a-f0-9]{64}$'
                  description: |
                    Raw SHA-256 of the file bytes, lowercase hex, NO 'sha256:' prefix.
                    (The .nodatasig sidecar uses 'sha256:<64hex>' format, but the API
                    body expects raw hex — see /kit/audit-chain-spec.md §8.)
                  example: '086fb29f1d7eaf2c4b9c3a8e5d1f6072c4a89b3e2f7d09e1a4b6c8d3f5a7b9c1'
                perceptual_hash:
                  type: string
                  description: 'Optional pHash for image content, format <algo>:<hex>'
                receipt_id:
                  type: string
                  description: Either receipt_id OR sidecar must be provided
                sidecar:
                  type: object
                  description: Full sidecar JSON (alternative to receipt_id)
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid: { type: boolean }
                  signer: { type: string }
                  signed_at: { type: string, format: date-time }
                  chain_index: { type: integer }
                  checks:
                    type: object
                    properties:
                      content_hash_matches: { type: boolean }
                      hmac_chain_intact: { type: boolean }
                      not_revoked: { type: boolean }
                      timestamp_in_window: { type: boolean }
        '429':
          description: Rate limit exceeded

  /verify-tree:
    post:
      summary: Verify a Merkle-signed folder
      description: |
        Re-derives the Merkle root from a manifest and confirms the root
        matches the signed receipt. Reports added/removed/modified files
        relative to the manifest.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [manifest, receipt_id]
              properties:
                manifest:
                  type: object
                  description: Tree manifest as produced by `nodata sign --dir`
                receipt_id:
                  type: string
                current_files:
                  type: array
                  description: Optional — current state to diff against manifest
                  items:
                    type: object
                    properties:
                      path: { type: string }
                      hash: { type: string }
                      size: { type: integer }

  /proof/chain:
    get:
      summary: Fetch a chain segment
      description: |
        Returns events `[from..to]` (inclusive) for a given tenant's chain.
        Used to verify continuity between two known receipts.
      parameters:
        - name: from
          in: query
          required: true
          schema: { type: string, description: receipt_id at start of segment }
        - name: depth
          in: query
          schema: { type: integer, default: 1, maximum: 100 }
      responses:
        '200':
          description: Chain segment
          content:
            application/json:
              schema:
                type: object
                properties:
                  events:
                    type: array
                    items: { type: object }

  /proof/{nickname}:
    get:
      summary: List public receipts for a signer nickname
      parameters:
        - name: nickname
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Recent public receipts for this nickname
          content:
            application/json:
              schema:
                type: object
                properties:
                  signer: { type: string }
                  receipts:
                    type: array
                    items: { type: object }

  /proof-certificate:
    get:
      summary: Generate a printable HTML certificate for a receipt
      parameters:
        - name: receipt_id
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: HTML certificate (printable)
          content:
            text/html: {}

  /audit/export:
    post:
      summary: Generate an audit-export ZIP for a tenant
      description: |
        In demo mode (default), returns a sample ZIP for any caller. In
        production mode (subscription gate enabled), requires a Bearer
        token with sufficient tier.
      responses:
        '200':
          description: ZIP file with summary.html, events.json, receipt-chain.csv, manifest.txt
          content:
            application/zip: {}

components:
  schemas:
    Receipt:
      type: object
      properties:
        schema: { type: string, example: 'nodatasig.v1' }
        receipt_id: { type: string }
        chain_index: { type: integer }
        prev_receipt_id: { type: string }
        tenant_id: { type: string }
        actor_device_id: { type: string }
        actor_nickname: { type: string }
        subject_kind: { type: string, enum: [file, directory, field, license, scan, finding, receipt, export] }
        subject_label: { type: string }
        content_hash: { type: string }
        signed_at: { type: string, format: date-time }
        event_hash: { type: string }
        chain_hmac: { type: string }
