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

# Get a Refusal Record by transaction ID

> Looks up a Refusal Record by businessTransactionId from Parmana's own storage. Unlike POST /refusal/verify, this route stays behind caller authentication and ownership scoping identically to GET /verify, GET /verification/{businessTransactionId}, and GET /trust-records/{businessTransactionId}: the underlying transaction content (signals, intent parameters) may be sensitive, so lookup is scoped even though independent signature verification (the other route) is not.




## OpenAPI

````yaml /openapi.bundled.yaml get /refusal/{businessTransactionId}
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 the liveness/readiness
    probes and documentation/verification routes that must be reachable with no
    credential: GET /health, GET /ready, GET /openapi.yaml, GET /documentation,
    GET /reference, POST /refusal/verify, POST /audit/verify, GET /keys/{keyId},
    and GET /.well-known/jwks.json. 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 Systems
    email: founder@parmanasystems.com
  license:
    name: Proprietary, source-available for evaluation only, see LICENSE
    url: https://github.com/pavancharak/AgentLabsBuildathon/blob/main/LICENSE
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: Policy Governance
    description: Maker-checker proposal, listing, approval, and rejection of policy changes
  - name: Refusal Records
    description: >-
      Durable, signed evidence that a policy decision rejected a transaction
      (RFC-0021)
  - name: Audit
    description: >-
      Signed caller-authentication audit events, independently
      third-party-verifiable
  - name: System
    description: Operational endpoints
paths:
  /refusal/{businessTransactionId}:
    get:
      tags:
        - Refusal Records
      summary: Get a Refusal Record by transaction ID
      description: >
        Looks up a Refusal Record by businessTransactionId from Parmana's own
        storage. Unlike POST /refusal/verify, this route stays behind caller
        authentication and ownership scoping identically to GET /verify, GET
        /verification/{businessTransactionId}, and GET
        /trust-records/{businessTransactionId}: the underlying transaction
        content (signals, intent parameters) may be sensitive, so lookup is
        scoped even though independent signature verification (the other route)
        is not.
      operationId: getRefusalRecord
      parameters:
        - name: businessTransactionId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Refusal Record found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/refusal-record.schema'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: >-
            No Refusal Record exists for this businessTransactionId, or it
            belongs to a different caller (ownership-scoped, same 404-not-403
            convention as every other scoped lookup in this API).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error.schema'
              examples:
                notFound:
                  summary: Real captured response
                  value:
                    error: Refusal Record not found.
components:
  schemas:
    refusal-record.schema:
      title: Refusal Record
      description: >-
        Durable, signed, independently verifiable evidence that a policy
        decision rejected a transaction (RFC-0021). Scope is deliberately
        narrow: covers PolicyEngine.evaluate REJECTs and SignalIntentBinder
        binding-violation REJECTs only, not caller-authentication failures or
        webhook signature failures, which are a separate, unsigned audit-sink
        capability. At most one Refusal Record exists per businessTransactionId.
      type: object
      additionalProperties: true
      required:
        - refusalRecordId
        - businessTransactionId
        - decision
        - evaluatedIntent
        - refusalRecordHash
        - signature
        - createdAt
      properties:
        refusalRecordId:
          type: string
          description: Unique Refusal Record identifier.
        businessTransactionId:
          type: string
          description: Business Transaction this refusal is about.
        decision:
          $ref: '#/components/schemas/decision.schema'
        evaluatedIntent:
          type: object
          description: >-
            The Intent snapshot the signals were evaluated against: target and
            parameters only, present for every refusal, not only binding
            violations.
          additionalProperties: true
          properties:
            target:
              type: string
            parameters:
              type: object
              additionalProperties: true
        bindingViolations:
          type: array
          description: >-
            Present only when the rejection came from SignalIntentBinder. Absent
            (not an empty array) for an ordinary PolicyEngine.evaluate REJECT
            that never reached binding-violation logic at all.
          items:
            type: object
            additionalProperties: true
            required:
              - signalKey
              - intentPath
              - signalValue
              - intentValue
            properties:
              signalKey:
                type: string
              intentPath:
                type: string
              signalValue: {}
              intentValue: {}
        submittedBy:
          type: string
          description: >-
            Authenticated caller who submitted the rejected request. Absent when
            caller authentication is disabled.
        refusalRecordHash:
          type: string
          description: >-
            Canonical hash of this Refusal Record, same convention as
            ExecutionTrustRecord.trustRecordHash.
        signature:
          type: object
          description: >-
            Cryptographic signature over the canonical Refusal Record, signed
            with the same key as ExecutionTrustRecord, one root of trust for
            both approvals and refusals.
          additionalProperties: true
          required:
            - algorithm
            - keyId
            - value
            - signedAt
          properties:
            algorithm:
              type: string
              examples:
                - ed25519
            keyId:
              type: string
              description: Identifier of the signing key.
            value:
              type: string
              description: Base64-encoded signature value.
            signedAt:
              type: string
              format: date-time
        createdAt:
          type: string
          format: date-time
          description: UTC timestamp when this Refusal Record was created.
      examples:
        - refusalRecordId: eddc5dd1-a791-4470-9534-11b3fc573ab8
          businessTransactionId: 353c73fb-5e87-4dbe-8bfc-c15c8f18d871
          decision:
            decisionId: 3919f4b6-cbc8-44ec-a6a1-8887ee85f314
            intentId: 4ba6b14a-c593-4f5c-ab58-dcef38a29364
            policy:
              name: vendor-payment
              version: 2.0.0
              schemaVersion: 1.0.0
            signals:
              vendorVerified: false
              invoiceVerified: true
              paymentApproved: true
              sufficientFunds: true
              paymentAmount: 1000
              riskScore: 5
              vendorId: vendor://payments
            outcome: REJECTED
            reason: Vendor payment rejected because the vendor has not been verified.
            evaluatedAt: '2026-09-15T03:27:45.666Z'
          evaluatedIntent:
            target: vendor://payments
            parameters:
              amount: 1000
              currency: USD
          createdAt: '2026-09-15T03:27:45.666Z'
          refusalRecordHash: 47d8200e839f9b4a1a53dba941e318553c9b024bc64d26c5b613e5ae2aeb65ca
          signature:
            algorithm: ed25519
            keyId: default
            value: >-
              tT32/iJ0bEDxjc+/KPeAegTBSrzpRFW14f9Vyv3Ykx+H/rLHcgd7SlFH/BAXut8sEH2mpo0smg82tSoXmZkpDQ==
            signedAt: '2026-09-15T03:27:45.668Z'
    error.schema:
      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
    decision.schema:
      title: Decision
      description: >-
        Immutable result of evaluating an Intent against a Policy. Decision does
        not create authority, grant authorization, or modify Intent; it only
        records the outcome of deterministic Policy evaluation.
      type: object
      additionalProperties: true
      required:
        - decisionId
        - intentId
        - policy
        - signals
        - outcome
        - evaluatedAt
      properties:
        decisionId:
          type: string
          description: Unique Decision identifier.
        intentId:
          type: string
          description: Intent evaluated by this Decision.
        policy:
          $ref: '#/components/schemas/policy.schema'
        signals:
          $ref: '#/components/schemas/signals.schema'
        outcome:
          type: string
          description: >-
            Policy evaluation outcome. There are no intermediate states: a
            Decision is always exactly one of these two values.
          enum:
            - APPROVED
            - REJECTED
        reason:
          type: string
          description: >-
            Human-readable explanation, taken from the matching Policy rule's
            outcome.reason.
        matchedRuleId:
          type: string
          description: >-
            Identifier of the Policy rule that matched, or "none" when no rule
            matched. Absent on a Decision built before this field existed
            (docs/VERIFICATION-GAPS.md G-44).
        evaluatedRules:
          type: integer
          description: >-
            Number of rules evaluated before reaching a match (or exhausting the
            rule list). Same optionality as matchedRuleId.
        matchedPath:
          type: array
          items:
            type: string
          description: >-
            Ordered rule-id trace evaluation walked to reach matchedRuleId. Same
            optionality as matchedRuleId.
        evaluatedAt:
          type: string
          format: date-time
          description: UTC timestamp when policy evaluation completed.
      examples:
        - decisionId: 9d69dc0b-333a-4be3-b09f-358fece806f3
          intentId: ae5865f6-181b-409a-90ec-1b4b8b8414ba
          policy:
            name: vendor-payment
            version: 2.0.0
            schemaVersion: 1.0.0
          signals:
            vendorVerified: true
            invoiceVerified: true
            paymentApproved: true
            sufficientFunds: true
            paymentAmount: 4500
            riskScore: 10
          outcome: APPROVED
          reason: >-
            Vendor payment authorized. Vendor verification, invoice
            verification, payment approval, funding, and risk assessment
            requirements were satisfied.
          matchedRuleId: approve-payment
          evaluatedRules: 1
          matchedPath:
            - approve-payment
          evaluatedAt: '2026-07-07T16:38:59.326Z'
    policy.schema:
      title: Policy Reference
      description: >-
        Exact Policy to evaluate. The client explicitly supplies name, version,
        and schemaVersion; Parmana does not automatically discover or select a
        policy. If no matching policy file exists at
        policies/{name}/{version}/policy.json, the request fails with a 404
        (policyId/policyVersion on POST /policies/validate) or a RUNTIME_ERROR
        (name/version elsewhere, from PolicyNotFoundError not otherwise mapped
        by the shared error handler in every route, see the error envelope
        note).
      type: object
      additionalProperties: true
      required:
        - name
        - version
        - schemaVersion
      properties:
        name:
          type: string
          description: >-
            Policy name. Required and non-empty. Parmana rejects an empty name
            with a 400.
          minLength: 1
        version:
          type: string
          description: >-
            Business policy version. Required and non-empty. Parmana rejects an
            empty version with a 400.
          minLength: 1
          examples:
            - 2.0.0
            - 1.0.0
        schemaVersion:
          type: string
          description: Signals schema version expected by the policy.
          examples:
            - 1.0.0
        contentHash:
          type: string
          description: >-
            sha256 of the canonicalized policy.json content actually loaded for
            this decision (G-24). Server-computed, never caller-settable; absent
            on a request-supplied PolicyReference and on a PolicyReference built
            before this field existed. Only present on the copy embedded in an
            Execution Trust Record's transaction.policy.
        governanceAnchor:
          type: object
          description: >-
            Whether the policy content above is traceable to a completed Policy
            Governance approval, resolved at decision time (G-45). Absent on a
            PolicyReference built before this field existed. Its presence does
            not imply POLICY_EXECUTION_VERIFICATION_ENFORCED is on -- only that
            the lookup ran and recorded what it found, which may honestly be "no
            approval record exists for this policy yet."
          additionalProperties: false
          required:
            - status
          properties:
            status:
              type: string
              enum:
                - VERIFIED
                - NO_APPROVAL_RECORD
                - SIGNATURE_INVALID
                - CONTENT_MISMATCH
            approvalRecordId:
              type: string
              description: >-
                The PolicyChangeApprovalRecord this anchor resolved against.
                Present only when a record was found at all -- absent for
                NO_APPROVAL_RECORD.
      examples:
        - name: vendor-payment
          version: 2.0.0
          schemaVersion: 1.0.0
        - name: vendor-payment
          version: 2.0.0
          schemaVersion: 1.0.0
          contentHash: 3f2504e04f8964e7ad0dbb0cf7fea1b4e0e1e0a3a1e1a4b6c8e0d5f6a7b8c9d0
          governanceAnchor:
            status: NO_APPROVAL_RECORD
    signals.schema:
      title: Signals
      description: >-
        Opaque runtime facts evaluated by the resolved Policy's rules. Parmana
        assigns no business meaning to these values and does not statically
        validate them beyond the Policy's own signalsSchema declaration (see
        policies/{name}/{version}/policy.json). Scaled integers, not floats, for
        numeric signals such as amounts (house convention across every reference
        policy).
      type: object
      additionalProperties: true
      examples:
        - vendorVerified: true
          invoiceVerified: true
          paymentApproved: true
          sufficientFunds: true
          paymentAmount: 4500
          riskScore: 10
  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 not listed as exempt in this document's
        top-level description. See /api-reference/authentication.

````