> ## 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.

# Validate that a Policy exists and is readable

> Checks that policies/{policyId}/{policyVersion}/policy.json exists and parses. Does NOT use the shared Error envelope for its failure responses: every status code (200, 400, 404) returns the same {valid, errors} shape. Field checks run in order: policyId first, then policyVersion; the first missing/empty field short-circuits with its own message. The one exception is 401: caller authentication runs in middleware, before this handler is ever reached, so a rejected caller gets the shared Error envelope ({"error": "authentication required"}), not {valid, errors}.




## OpenAPI

````yaml /openapi.bundled.yaml post /policies/validate
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:
  /policies/validate:
    post:
      tags:
        - Policies
      summary: Validate that a Policy exists and is readable
      description: >
        Checks that policies/{policyId}/{policyVersion}/policy.json exists and
        parses. Does NOT use the shared Error envelope for its failure
        responses: every status code (200, 400, 404) returns the same {valid,
        errors} shape. Field checks run in order: policyId first, then
        policyVersion; the first missing/empty field short-circuits with its own
        message. The one exception is 401: caller authentication runs in
        middleware, before this handler is ever reached, so a rejected caller
        gets the shared Error envelope ({"error": "authentication required"}),
        not {valid, errors}.
      operationId: validatePolicy
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/policy-validate-request.schema'
            examples:
              vendor-payment:
                summary: Real captured request
                value:
                  policyId: vendor-payment
                  policyVersion: 2.0.0
              notFound:
                summary: Real captured request, unknown policy
                value:
                  policyId: does-not-exist
                  policyVersion: 9.9.9
      responses:
        '200':
          description: Policy exists and is readable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/policy-validate-response.schema'
              examples:
                vendor-payment:
                  summary: Real captured response
                  value:
                    valid: true
                    errors: []
        '400':
          description: policyId or policyVersion missing/empty.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/policy-validate-response.schema'
              examples:
                missingField:
                  summary: Real captured response
                  value:
                    valid: false
                    errors:
                      - policyVersion is required.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: >-
            No policy.json exists at the requested name/version
            (PolicyNotFoundError, caught locally and re-shaped, not routed
            through the shared error handler).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/policy-validate-response.schema'
              examples:
                notFound:
                  summary: Real captured response
                  value:
                    valid: false
                    errors:
                      - Policy 'does-not-exist' version '9.9.9' was not found.
components:
  schemas:
    policy-validate-request.schema:
      $schema: https://json-schema.org/draft/2020-12/schema
      $id: https://schemas.parmana.ai/requests/policy-validate-request.schema.json
      title: Policy Validate Request
      description: >-
        Request payload for POST /policies/validate. policyId and policyVersion
        are each required non-empty strings, checked in that order; each
        missing/empty field is rejected with its own 400 and a distinct message.
      type: object
      additionalProperties: true
      required:
        - policyId
        - policyVersion
      properties:
        policyId:
          type: string
          minLength: 1
          description: >-
            Policy name, matching the directory name under the configured policy
            directory.
        policyVersion:
          type: string
          minLength: 1
          description: Policy version, matching the version subdirectory.
      examples:
        - policyId: vendor-payment
          policyVersion: 2.0.0
    policy-validate-response.schema:
      $schema: https://json-schema.org/draft/2020-12/schema
      $id: >-
        https://schemas.parmana.ai/responses/policy-validate-response.schema.json
      title: Policy Validate Response
      description: >-
        Response returned by POST /policies/validate on every status code (200,
        400, and 404 all use this exact shape). This endpoint does NOT use the
        shared Error envelope (../common/error.schema.json) for its failure
        responses.
      type: object
      additionalProperties: false
      required:
        - valid
        - errors
      properties:
        valid:
          type: boolean
          description: Whether the referenced policy exists and is readable.
        errors:
          type: array
          description: >-
            Empty when valid is true; otherwise exactly one human-readable
            message.
          items:
            type: string
      examples:
        - valid: true
          errors: []
        - valid: false
          errors:
            - Policy 'does-not-exist' version '9.9.9' was not found.
        - valid: false
          errors:
            - policyVersion is required.
    error.schema:
      $schema: https://json-schema.org/draft/2020-12/schema
      $id: https://schemas.parmana.ai/common/error.schema.json
      title: Error Response
      description: >-
        Shared error envelope produced by
        packages/api/src/middleware/error-handler.ts and by every route's inline
        validation checks. error is always a plain human-readable string (never
        a nested object). code is present only when the failure was a
        RuntimeError subclass reaching the centralized error handler
        (VerificationFailedError, ReceiptGenerationError, or an uncategorized
        RuntimeError); it is absent from every inline route-level check
        (businessTransactionId format/required checks) and from
        BusinessTransactionValidationError, PolicyValidationError,
        SignalValidationError, PolicyNotFoundError,
        DuplicateBusinessTransactionError, and the generic 500 fallback. POST
        /policies/validate does NOT use this envelope at all. See its own
        response schema. For the triggering condition and recommended caller
        action behind any specific error/code/status combination, see the Error
        catalog at /api-reference/error-catalog.
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
        code:
          type: string
          description: >-
            Stable machine-readable error code. Only present for errors that
            reach the handler as a RuntimeError.
          examples:
            - RUNTIME_ERROR
            - VERIFICATION_FAILED
            - RECEIPT_GENERATION_FAILED
      examples:
        - error: businessTransactionId must be a valid UUID.
        - error: >-
            Business Transaction 'eed2a972-1bf5-4166-8472-761f76fbf1b2' already
            exists.
        - error: >-
            Execution rejected: Vendor payment rejected because the assessed
            payment risk exceeds the maximum permitted threshold.
          code: RUNTIME_ERROR
  responses:
    Unauthorized:
      description: >-
        Missing or invalid caller credential (StaticKeyAuthenticator returned no
        identity). Real captured response,
        packages/api/src/middleware/caller-auth.ts.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error.schema'
          examples:
            authRequired:
              summary: Real captured response, missing or invalid Authorization header
              value:
                error: authentication required
  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.

````