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

# Get decision evidence

> Retrieve, for every rule of the ruleset version pinned to the decision, its outcome and —
for each rule that fired — the evidence: the resolved operands of a comparison, the count /
window / threshold of a velocity rule, the entry a blacklist rule matched. The trace uses
the same entry shape as [`simulate`](/products/specter/api-reference/rulesets/simulate-ruleset).

Evidence is **replayed** where the input is frozen — the pinned ruleset re-evaluated
against the stored payload, deterministically — and **captured** at decision time where
it is not (velocity counters, blacklist matches). Each entry states `evidence_source` and
`replay_fidelity`. Replay reproduces only what retention preserved: a field whose scope was
not retained, or stored in reduced form, is absent to the replayer and the rule abstains on
replay (`reduced`). HMAC outputs and the credential fingerprint do reproduce. Backend rules
are never re-invoked. A `replayed_verdict` that differs from `decision` is therefore an
expected artifact of partial retention, not an error; it is null whenever any entry is
`reduced` or a backend rule participated.

Availability follows the stored payload's opt-in retention: `200` with `retained: false`
when nothing was kept, `404` for an unknown id.




## OpenAPI

````yaml /products/specter/openapi.yaml get /api/decisions/{id}/evidence
openapi: 3.1.0
info:
  contact:
    email: support@hellgate.io
    name: Starfish GmbH & Co. KG
    url: https://hellgate.io/cpa/specter
  description: Composable decision engine and fraud prevention service.
  license:
    name: Hellgate API Terms
    url: https://hellgate.io/terms-and-conditions
  title: Specter API
  version: '1.0'
servers:
  - description: Managed instance of Specter
    url: https://{instance}.{env}.on-hellgate.cloud
    variables:
      instance:
        default: my-instance
        description: Your unique instance slug, provided during onboarding.
      env:
        default: eu1
        description: Deployment environment (currently eu1).
security: []
tags:
  - description: Evaluate transactions and retrieve decision results.
    name: Decisions
  - description: Close decisions that were flagged for manual review.
    name: Resolutions
  - description: Report payment lifecycle events for a prior decision.
    name: Lifecycle Events
  - description: Manage rulesets and their activation lifecycle.
    name: Rulesets
  - description: Register and version custom decision-payload schemas.
    name: Schemas
  - description: Configure interceptors and intercept live payment requests.
    name: Interceptors
  - description: Subscribe to decision and event notifications.
    name: Webhooks
  - description: Manage blocked field values.
    name: Blacklist
paths:
  /api/decisions/{id}/evidence:
    get:
      tags:
        - Decisions
      summary: Get decision evidence
      description: >
        Retrieve, for every rule of the ruleset version pinned to the decision,
        its outcome and —

        for each rule that fired — the evidence: the resolved operands of a
        comparison, the count /

        window / threshold of a velocity rule, the entry a blacklist rule
        matched. The trace uses

        the same entry shape as
        [`simulate`](/products/specter/api-reference/rulesets/simulate-ruleset).


        Evidence is **replayed** where the input is frozen — the pinned ruleset
        re-evaluated

        against the stored payload, deterministically — and **captured** at
        decision time where

        it is not (velocity counters, blacklist matches). Each entry states
        `evidence_source` and

        `replay_fidelity`. Replay reproduces only what retention preserved: a
        field whose scope was

        not retained, or stored in reduced form, is absent to the replayer and
        the rule abstains on

        replay (`reduced`). HMAC outputs and the credential fingerprint do
        reproduce. Backend rules

        are never re-invoked. A `replayed_verdict` that differs from `decision`
        is therefore an

        expected artifact of partial retention, not an error; it is null
        whenever any entry is

        `reduced` or a backend rule participated.


        Availability follows the stored payload's opt-in retention: `200` with
        `retained: false`

        when nothing was kept, `404` for an unknown id.
      operationId: decisions_evidence
      parameters:
        - description: Decision ID
          in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DecisionEvidence'
          description: Evidence and replay trace, or an explicit not-retained result
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forbidden'
          description: Forbidden
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: Not found
      callbacks: {}
      security:
        - bearerAuth: []
components:
  schemas:
    DecisionEvidence:
      description: >-
        Per-rule evidence for a recorded decision, with the replay trace that
        produced it. The trace uses the same entry vocabulary as the simulation
        endpoint.
      example:
        decision_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        decision: REVIEW
        retained: true
        ruleset_id: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        ruleset_version: 3
        schema:
          name: transaction
        replayed_at: '2026-08-19T10:16:02Z'
        replayed_verdict: REVIEW
        trace:
          - rule_id: r_amount
            name: High amount
            action: REVIEW
            type: condition
            outcome: fired
            evidence_source: replayed
            replay_fidelity: full
            fields:
              - path: $.transaction.amount
                value: 4900
            derivations:
              comparison:
                operator: gt
                left:
                  path: $.transaction.amount
                  value: 4900
                right:
                  path: null
                  value: 1000
      properties:
        decision:
          description: The verdict as originally recorded on the decision.
          enum:
            - ALLOW
            - BLOCK
            - REVIEW
            - PROVISIONAL
          type: string
        decision_id:
          format: uuid
          type: string
        replayed_at:
          description: >-
            When this replay ran. Replay is deterministic — repeated calls
            agree.
          format: date-time
          type:
            - string
            - 'null'
        replayed_verdict:
          description: >-
            The verdict reconstructed by replaying the pinned ruleset against
            the frozen payload. Non-null only when every entry in `trace`
            replayed at full fidelity and no backend rule participated in the
            original decision — in that case it equals `decision`. Null when
            `retained` is false, when any referenced field was absent to the
            replayer (see `replay_fidelity`), or when the recorded verdict arose
            through a backend rule, which replay never re-invokes. A null here
            means "not reconstructible", not "reconstruction failed".
          enum:
            - ALLOW
            - BLOCK
            - REVIEW
          type:
            - string
            - 'null'
        retained:
          description: >-
            False when no evidence was kept for this decision. A successful
            response, not an error.
          type: boolean
        ruleset_id:
          description: The ruleset pinned to the decision and resolved for replay.
          format: uuid
          type:
            - string
            - 'null'
        ruleset_version:
          description: >-
            The exact version pinned to the decision — not the context's current
            ACTIVE version.
          type:
            - integer
            - 'null'
        schema:
          description: >-
            The (schema, version) the decision was evaluated against. Null when
            nothing was retained.
          oneOf:
            - $ref: '#/components/schemas/SchemaBinding'
            - type: 'null'
        trace:
          description: >-
            One entry per rule of the pinned ruleset, in published evaluation
            order. Null when `retained` is false — replay needs the frozen
            payload and does not fall back to live inputs. Also null when the
            decision pinned no ruleset (the block-all safeguard), even though
            `retained` is true.
          items:
            $ref: '#/components/schemas/EvidenceTraceEntry'
          type:
            - array
            - 'null'
      required:
        - decision_id
        - decision
        - retained
      title: DecisionEvidence
      type: object
    Unauthorized:
      description: No valid authentication was provided.
      example:
        classifier: UNAUTHORIZED
        code: 401
        message: No valid means of authentication was provided
      properties:
        classifier:
          enum:
            - UNAUTHORIZED
          type: string
        code:
          enum:
            - 401
          type: integer
        message:
          type: string
      required:
        - classifier
        - code
        - message
      title: Unauthorized
      type: object
    Forbidden:
      description: The token lacks the scope required for this operation.
      example:
        classifier: FORBIDDEN
        code: 403
        message: Not allowed to access this resource or feature
      properties:
        classifier:
          enum:
            - FORBIDDEN
          type: string
        code:
          enum:
            - 403
          type: integer
        message:
          type: string
      required:
        - classifier
        - code
        - message
      title: Forbidden
      type: object
    NotFound:
      description: The requested resource does not exist.
      example:
        classifier: NOT_FOUND
        code: 404
        message: The requested resource does not exist
      properties:
        classifier:
          enum:
            - NOT_FOUND
          type: string
        code:
          enum:
            - 404
          type: integer
        message:
          type: string
      required:
        - classifier
        - code
        - message
      title: NotFound
      type: object
    SchemaBinding:
      description: >-
        A ruleset's declared (schema, version) pair. name references a registry
        entry; version is required for custom schemas and absent for built-ins,
        whose version is implicit and advances only via Specter releases. Set at
        ruleset creation and immutable for the life of that ruleset version —
        rebinding a context means publishing a new ruleset version with the new
        binding and activating it. Rulesets that predate the registry surface
        the launch-backfilled transaction binding.
      properties:
        name:
          example: transaction
          type: string
        version:
          description: Registry version for custom schemas. Absent for built-in schemas.
          example: 1
          type:
            - integer
            - 'null'
      required:
        - name
      title: SchemaBinding
      type: object
    EvidenceTraceEntry:
      allOf:
        - $ref: '#/components/schemas/TraceEntry'
        - properties:
            evidence_source:
              description: >-
                How this entry's evidence was obtained. replayed — re-derived by
                evaluating the pinned ruleset against the frozen payload.
                captured — recorded as a decision-time fact because it cannot be
                reconstructed (velocity counts, blacklist matches). none — the
                rule did not fire, so it carries no evidence; "why did a rule
                not fire" is out of scope.
              enum:
                - replayed
                - captured
                - none
              type: string
            replay_fidelity:
              description: >-
                Whether replay reproduced this entry against the same inputs the
                original evaluation consumed. full — every field the rule
                references was retained in its evaluated form, so outcome is
                what happened at decision time. reduced — at least one
                referenced field was absent to the replayer (scope not retained,
                or stored in reduced form), so the rule abstained on replay and
                outcome does NOT necessarily match the original; consult
                unreproducible_fields. not_applicable — the entry's evidence is
                captured rather than replayed, so fidelity does not arise.
              enum:
                - full
                - reduced
                - not_applicable
              type: string
            unreproducible_fields:
              description: >-
                Only when replay_fidelity is "reduced" — the field paths that
                were absent to the replayer. Distinct from absent_fields, which
                names fields absent from the payload when the decision was
                originally made.
              items:
                type: string
              type:
                - array
                - 'null'
          required:
            - evidence_source
            - replay_fidelity
          type: object
      description: >-
        A TraceEntry from a recorded decision rather than a simulation.
        Identical shape; adds the provenance of the entry's evidence and whether
        replay reproduced it faithfully. On the evidence surface a velocity
        derivation always carries live_read false — the count is the captured
        decision-time reading.
      title: EvidenceTraceEntry
    TraceEntry:
      allOf:
        - $ref: '#/components/schemas/TriggeredRule'
        - properties:
            absent_fields:
              description: >-
                Only when outcome is "abstained" — the field path(s) that
                resolved absent, e.g. "$.customer.email".
              items:
                type: string
              type:
                - array
                - 'null'
            absorbed_operands:
              description: >-
                Only when outcome is "abstained" and no path resolved absent —
                the operand(s) that absorbed the predicate while resolving to a
                present value, and why. non_list_operand — a membership (in /
                not_in) operand resolved to a value that is not an array, so the
                set test is undefined and the predicate abstains without
                anything having gone absent. Together with absent_fields this
                makes every abstention self-explaining.
              items:
                properties:
                  path:
                    description: >-
                      The operand's field path, or "(const)" where the operand
                      is a rule literal.
                    example: $.label
                    type: string
                  reason:
                    enum:
                      - non_list_operand
                    type: string
                required:
                  - path
                  - reason
                type: object
              type:
                - array
                - 'null'
            derivations:
              description: >-
                Platform-internal derivations behind the outcome. Only the keys
                the rule exercises are present. This envelope is the extension
                point downstream grammar extensions render their per-construct
                detail into without changing the core entry shape. comparison
                and blacklist are rendered by the decision evidence surface (GET
                /api/decisions/{id}/evidence); the simulation trace renders
                filter_chains, hmac and velocity.
              properties:
                blacklist:
                  description: >-
                    Present on a fired blacklist rule. Captured at decision time
                    rather than replayed — a blacklist is mutable state, so
                    re-looking-up against today's entries could not reconstruct
                    the match as it stood. Later edits to the blacklist,
                    including deleting the matched entry, do not rewrite it.
                  properties:
                    entry_id:
                      description: The blacklist entry that matched.
                      format: uuid
                      type: string
                    field_path:
                      example: $.credential_fingerprint
                      type: string
                    matched_value:
                      description: >-
                        The looked-up value, rendered per the field's scope
                        marker — "[REDACTED]" for pii / pci-pan.
                  required:
                    - field_path
                    - entry_id
                  type: object
                comparison:
                  description: >-
                    Present on a fired comparison rule. Both resolved operands
                    and the operator, each operand rendered per its own scope
                    marker — so a pii operand shows its path and a sentinel
                    while an any operand on the other side of the same
                    comparison shows its value.
                  properties:
                    left:
                      $ref: '#/components/schemas/ResolvedOperand'
                    operator:
                      enum:
                        - eq
                        - neq
                        - lt
                        - lte
                        - gt
                        - gte
                        - in
                        - not_in
                      type: string
                    right:
                      $ref: '#/components/schemas/ResolvedOperand'
                  required:
                    - operator
                    - left
                    - right
                  type: object
                filter_chains:
                  items:
                    properties:
                      output:
                        description: Final chain output, redacted per inherited scope.
                      source:
                        example: $.customer.email
                        type: string
                      steps:
                        items:
                          properties:
                            filter:
                              example: downcase()
                              type: string
                            output:
                              description: Step output, redacted per inherited scope.
                          required:
                            - filter
                          type: object
                        type: array
                    required:
                      - source
                      - steps
                    type: object
                  type: array
                hmac:
                  properties:
                    inputs:
                      description: >-
                        Contributing field paths (paths only, never values); a
                        const literal renders as "(const)". The filters an input
                        was folded through render as a filter_chains entry for
                        that path.
                      items:
                        type: string
                      type: array
                    output:
                      description: >-
                        Full HMAC-SHA256 hex, without the `hmc_` prefix the
                        engine compares against. HMAC outputs are any-scoped by
                        definition and render unredacted — to pin a rule to this
                        fingerprint, compare the hmac operand against the
                        literal `hmc_` + this value.
                      pattern: ^[0-9a-f]{64}$
                      type: string
                  required:
                    - inputs
                    - output
                  type: object
                velocity:
                  properties:
                    canonical_text:
                      description: Human-readable canonical form of the counter definition.
                      type: string
                    counter_id:
                      description: >-
                        Stable canonical counter identifier — confirms
                        counter-sharing intent across rules. Value-free — the
                        counted value contributes only an instance-keyed digest,
                        so a counter keyed by a pii field neither renders that
                        value nor lets a holder of a candidate value reproduce
                        the identifier and test for it.
                      type: string
                    live_read:
                      description: >-
                        True on the simulate path — the value is read from live
                        counter state and may differ between identical runs.
                        False wherever the value is a counter reading captured
                        at decision time and is therefore stable across repeated
                        reads.
                      type: boolean
                    threshold:
                      description: The rule's configured threshold.
                      type: integer
                    value:
                      description: The counter value the rule evaluated against.
                      type: integer
                    window_seconds:
                      description: The rule's configured rolling window.
                      type: integer
                  required:
                    - canonical_text
                    - counter_id
                    - live_read
                    - threshold
                    - value
                    - window_seconds
                  type: object
              type:
                - object
                - 'null'
            fields:
              description: >-
                Field values the rule's predicate resolved, rendered per scope
                marker — any renders the value; pii / pci-pan / pci-sad render
                "[REDACTED]" with the path visible. Filtered values inherit the
                strictest scope of their chain's inputs. A path addressing an
                object or array renders each descendant per its own marker. A
                path that resolved absent carries no value at all.
              items:
                properties:
                  path:
                    example: $.transaction.amount
                    type: string
                  value:
                    description: Rendered value or "[REDACTED]".
                required:
                  - path
                type: object
              type:
                - array
                - 'null'
            outcome:
              description: >-
                fired — predicate matched, the rule's action contributes to the
                verdict. not_fired — predicate evaluated to false. abstained —
                the predicate absorbed (absent-attribute fail-skip),
                distinguished from not_fired, and always names its cause —
                absent_fields where a reference resolved to absent,
                absorbed_operands where one resolved present but unusable.
                not_simulated — backend rule reached but not invoked (see
                backend_results). not_evaluated — evaluation never reached this
                rule (see skip_reason).
              enum:
                - fired
                - not_fired
                - abstained
                - not_simulated
                - not_evaluated
              type: string
            skip_reason:
              description: >-
                Only when outcome is "not_evaluated". short_circuited — an
                earlier rule fired BLOCK. verdict_suppressed — an earlier
                backend rule was reached and stopped evaluation. Absent on a
                rule that is disabled and therefore never evaluated — nothing
                skipped it.
              enum:
                - short_circuited
                - verdict_suppressed
              type:
                - string
                - 'null'
          required:
            - outcome
          type: object
      description: >-
        Extends the published TriggeredRule entry (rule_id, name, action, type)
        with the simulation outcome and the derivations behind it.
      title: TraceEntry
    TriggeredRule:
      properties:
        action:
          enum:
            - BLOCK
            - REVIEW
          example: BLOCK
          type:
            - string
            - 'null'
        name:
          example: Block USD
          type:
            - string
            - 'null'
        rule_id:
          example: r1
          type: string
        type:
          enum:
            - condition
            - blacklist
            - backend
            - backend_group
          example: condition
          type: string
      title: TriggeredRule
      type: object
    ResolvedOperand:
      description: >-
        One side of a comparison as it resolved during evaluation. `path` is
        present for a field reference and null for a literal. `value` is
        rendered per the operand's scope marker — "[REDACTED]" for pii / pci-pan
        — so evidence names which rule fired on which path without disclosing a
        protected value. A `pci-sad` field is excluded from evidence entirely
        and can never appear as an operand.
      properties:
        path:
          example: $.transaction.amount
          type:
            - string
            - 'null'
        value:
          description: Rendered value or "[REDACTED]".
      title: ResolvedOperand
      type: object
  securitySchemes:
    bearerAuth:
      bearerFormat: JWT
      description: >-
        HS256-signed JWT bearer token, obtained via the OAuth2
        client-credentials grant (see Authentication).
      scheme: bearer
      type: http

````