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

# Fetch a public signing key for independent, offline verification

> Deliberately unauthenticated, like GET /audit/verify and GET /refusal/verify — a third party (regulator, auditor, customer tool) fetching the key it needs to independently verify a signature cannot be required to already hold a Parmana credential to reach it. Returns the current or any still-retained historical key's public half; a keyId whose private key was rotated away from is still resolvable here as long as its files were not deleted (PQC audit RED-3, docs/VERIFICATION-GAPS.md). See packages/crypto/src/OfflineVerifier.ts (and its Python counterpart, python/parmana/crypto/ offline_verifier.py) for a reference verifier that consumes exactly this response's `pem` field with zero further network calls.




## OpenAPI

````yaml /openapi.bundled.yaml get /keys/{keyId}
openapi: 3.1.0
info:
  title: Parmana API
  version: 1.0.0
  description: >
    Parmana is an Execution Trust Infrastructure that ensures there is no gap
    between what humans decide and what AI systems do. The API enables creation,
    execution, verification, replay, and auditing of Business Transactions
    through cryptographically verifiable Execution Trust Records.


    **Every route requires a caller bearer key, except GET /health.** Send
    `Authorization: Bearer <key>` on every other request. Keys are issued by
    `scripts/generate-api-key.ts` and configured server-side via
    `PARMANA_API_KEYS`; only a hash of each key is ever held by the server,
    verified in constant time. A missing or invalid credential returns 401
    before a Business Transaction is even constructed, independent of Policy
    evaluation and gateway attestation, see
    `packages/api/src/middleware/caller-auth.ts` and
    [Authentication](/api-reference/authentication). Local development may set
    `PARMANA_AUTH_DISABLED=true` to skip this middleware entirely; that flag
    must never be set in a real deployment.
  contact:
    name: Parmana
    email: support@parmana.ai
  license:
    name: Apache-2.0
    identifier: Apache-2.0
servers:
  - url: http://localhost:3000
    description: Local (packages/api, PORT env var, default 3000)
security:
  - bearerAuth: []
tags:
  - name: Execution
    description: >-
      Executes a Business Transaction through the complete Execution Trust
      pipeline
  - name: Transactions
    description: Business Transaction creation and retrieval
  - name: Verification
    description: Deterministic verification of an Execution Trust Record
  - name: Receipts
    description: Cryptographically signed Execution Trust Receipts
  - name: Trust Records
    description: Execution Trust Record retrieval
  - name: Replay
    description: Deterministic replay of a recorded Execution Trust Record
  - name: Policies
    description: Policy existence/readability check
  - name: System
    description: Operational endpoints
paths:
  /keys/{keyId}:
    get:
      tags:
        - System
      summary: Fetch a public signing key for independent, offline verification
      description: >
        Deliberately unauthenticated, like GET /audit/verify and GET
        /refusal/verify — a third party (regulator, auditor, customer tool)
        fetching the key it needs to independently verify a signature cannot be
        required to already hold a Parmana credential to reach it. Returns the
        current or any still-retained historical key's public half; a keyId
        whose private key was rotated away from is still resolvable here as long
        as its files were not deleted (PQC audit RED-3,
        docs/VERIFICATION-GAPS.md). See packages/crypto/src/OfflineVerifier.ts
        (and its Python counterpart, python/parmana/crypto/ offline_verifier.py)
        for a reference verifier that consumes exactly this response's `pem`
        field with zero further network calls.
      operationId: getKey
      parameters:
        - name: keyId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The requested public key.
          content:
            application/json:
              schema:
                type: object
                required:
                  - keyId
                  - algorithm
                  - use
                  - pem
                properties:
                  keyId:
                    type: string
                  algorithm:
                    type: string
                    description: >
                      The key's actual algorithm, derived from the key material
                      itself (asymmetricKeyType), not a global config value.
                  use:
                    type: string
                    enum:
                      - sig
                  pem:
                    type: string
                    description: PEM-encoded SPKI public key (RFC 7468).
                  jwk:
                    type: object
                    description: >
                      Node's native JWK export for this key's algorithm, when
                      available. Ed25519 exports as kty "OKP"; ML-DSA-65 exports
                      as kty "AKP" (the IETF JOSE/COSE key type for ML-DSA — not
                      an identifier this codebase invented). Omitted, not null,
                      when unavailable.
        '404':
          description: No key exists for the given keyId.
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        Caller API key issued by scripts/generate-api-key.ts. Sent as
        Authorization: Bearer <key>. Verified against a stored SHA-256 hash in
        constant time by packages/api/src/auth/StaticKeyAuthenticator.ts.
        Required on every route except GET /health. See
        /api-reference/authentication.

````