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

# Look up one recent decision by the decision_id from the API response or

> the outcome.produced webhook. The analytics log is bounded and ephemeral: a 404 means 'rotated out of the recent window or never existed' — billing truth lives…

the `outcome.produced` webhook. The analytics log is bounded and
ephemeral: a 404 means 'rotated out of the recent window or never
existed' — billing truth lives in the metering pipeline.

**Required scope:** `read`

### Path parameters

<ParamField path="id" type="string" required />

### Response

`DecisionRecord`

<ResponseField name="batch" type="boolean" required>
  True when the decision came through `/v1/decisions/batch`.
</ResponseField>

<ResponseField name="billable" type="boolean" required />

<ResponseField name="cited_rules" type="string[]" required>
  Rule ids cited in the proof chain.
</ResponseField>

<ResponseField name="confidence" type="number (double)">
  The confidence the decision reported, in \[0, 1]. Stored so calibration can bucket decisions by what they claimed and compare against what actually happened (see `outcome`).
</ResponseField>

<ResponseField name="cost_micros" type="integer (int64)" required />

<ResponseField name="decision" type="string" required>
  `approved | denied | refused`.
</ResponseField>

<ResponseField name="decision_id" type="string">
  The `decision_id` returned in the API response and carried by the `outcome.produced` webhook — the correlation key for audits.
</ResponseField>

<ResponseField name="dropped_citations" type="string[]">
  Org rules that fired during hydration but were dropped from the proof as unrelated — the audit record of standing-rule noise per decision.
</ResponseField>

<ResponseField name="external_ref" type="string">
  Optional client-supplied correlation key (their order id, case id, claim number…). This is what closes the outcome loop from REAL events: a chargeback or override webhook knows the order id, not our `decision_id`, so `POST /v1/decisions/outcome-by-ref` records the outcome by this key. `None` when the caller didn't supply one.
</ResponseField>

<ResponseField name="latency_ms" type="integer (int64)" required />

<ResponseField name="missing_predicates" type="string[]">
  Deduped predicate names from a refused decision's `refusal.missing_facts` — the KB coverage gaps that blocked it. Empty for approvals/denials and safety-gated refusals (which carry none).
</ResponseField>

<ResponseField name="outcome" type="string">
  The real-world outcome, recorded AFTER the fact via `POST /v1/decisions/&#123;id&#125;/outcome`: `honored` (the decision held up), `reversed` (e.g. an approved refund was charged back), `overridden` (a human changed it), or `escalated`. `None` until reported. This is the ground truth that turns confidence from a heuristic into a calibrated, measurable number.
</ResponseField>

<ResponseField name="query" type="string" required>
  The decision query, truncated to 200 chars for memory hygiene.
</ResponseField>

<ResponseField name="request" type="object">
  <Expandable title="request">
    <ResponseField name="action" type="string" />

    <ResponseField name="authorization_goal" type="object">
      <Expandable title="authorization_goal">
        <ResponseField name="args" type="Arg[]" required />

        <ResponseField name="name" type="string" required />

        <ResponseField name="negated" type="boolean">
          Negation-as-failure for a rule CONDITION: `not fraud_flagged(?o, ?r)`. Meaningful only on rule conditions (ignored on facts and conclusions). Defaulted and skipped-when-false so existing payloads are unchanged. Without this the negation was silently dropped and the condition read as POSITIVE — a fraud-flagged subject slipped a `not fraud_flagged` guard.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="confidence_threshold" type="number (double)" />

    <ResponseField name="facts" type="RecursiveChatFactInput[]">
      <Expandable title="RecursiveChatFactInput">
        <ResponseField name="confidence" type="number (double)" />

        <ResponseField name="predicate" type="RecursiveChatPredicateInput" required />

        <ResponseField name="source" type="string" />
      </Expandable>
    </ResponseField>

    <ResponseField name="hydrate_org_context" type="boolean" />

    <ResponseField name="max_depth" type="integer" />

    <ResponseField name="mode" type="string" />

    <ResponseField name="query" type="string" required />

    <ResponseField name="rules" type="RecursiveChatRuleInput[]">
      <Expandable title="RecursiveChatRuleInput">
        <ResponseField name="category" type="string" />

        <ResponseField name="constraints" type="any[]" />

        <ResponseField name="description" type="string" />

        <ResponseField name="effect" type="object" />

        <ResponseField name="enabled" type="boolean" />

        <ResponseField name="id" type="string" />

        <ResponseField name="if" type="RecursiveChatPredicateInput[]" required />

        <ResponseField name="name" type="string" required />

        <ResponseField name="priority" type="integer (int32)" />

        <ResponseField name="then" type="RecursiveChatPredicateInput[]" required />
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="request_policy_hash" type="string">
  `sha256:&lt;hex>` over the request-scoped policy the decision was evaluated against (see `DecisionProof::request_policy_hash`) — lets an audit confirm a replay uses the same policy inputs.
</ResponseField>

<ResponseField name="timestamp" type="string (date-time)" required />

### Status codes

| Code  | Meaning                                            |
| ----- | -------------------------------------------------- |
| `200` | The decision record                                |
| `401` | Unauthorized — missing or invalid credentials      |
| `403` | Forbidden — the key/token lacks the required scope |
| `404` | Not in the retained window                         |
| `429` | Rate limited — see Retry-After / X-RateLimit-Reset |

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET \
    --url 'https://api.nsr.stateset.com/v1/decisions/{id}' \
    --header 'X-API-Key: YOUR_API_KEY'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "batch": true,
    "billable": true,
    "cited_rules": [
      "string"
    ],
    "confidence": 7.5,
    "cost_micros": 1,
    "decision": "string",
    "decision_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "dropped_citations": [
      "string"
    ],
    "external_ref": "string",
    "latency_ms": 250,
    "missing_predicates": [
      "string"
    ],
    "outcome": "string",
    "query": "string",
    "request": {
      "action": "string",
      "authorization_goal": {
        "args": [],
        "name": "Two-Person Tent",
        "negated": true
      },
      "confidence_threshold": 7.5,
      "facts": [
        {
          "confidence": null,
          "predicate": null,
          "source": null
        }
      ],
      "hydrate_org_context": true,
      "max_depth": 1,
      "mode": "string",
      "query": "string",
      "rules": [
        {
          "category": null,
          "constraints": null,
          "description": null,
          "effect": null,
          "enabled": null,
          "id": null,
          "if": null,
          "name": null,
          "priority": null,
          "then": null
        }
      ]
    },
    "request_policy_hash": "string",
    "timestamp": "2026-08-31T14:22:05Z"
  }
  ```
</ResponseExample>
