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

# Answer a queue of tickets in one call.

> **Required scope:** write

**Required scope:** `write`

### Request body

`BatchAnswerRequest`

<ParamField body="items" type="AnswerRequest[]" required />

### Response

`BatchAnswerResponse`

<ResponseField name="answers" type="AnswerResponse[]" required>
  <Expandable title="AnswerResponse">
    <ResponseField name="auto_send" type="boolean" required>
      True when this can ship untouched. False means read `requires_human`.
    </ResponseField>

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

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

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

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

        <ResponseField name="dropped_citations" type="string[]">
          Org rules the engine fired during hydration that were dropped from `proof.cited_rules` as unrelated to this decision. Persistently non-empty values mean a standing rule with permanently satisfied premises fires on every hydrated decision — scope or prune it.
        </ResponseField>

        <ResponseField name="evaluated_goal" type="string">
          Exact predicate evaluated as the permit target. Absent for legacy requests that relied on action/query inference.
        </ResponseField>

        <ResponseField name="grounding" type="DecisionGrounding" required />

        <ResponseField name="gss_machine" type="GssMachineGroundingSnapshot" required />

        <ResponseField name="plain_explanation" type="string" required>
          Deterministic, proof-derived, business-readable 'why' — distinct from `rationale` (engine narration): 'Approved to issue a refund for order 9412: the return for order 9412 was received and order 9412 passed inspection.' Always present.
        </ResponseField>

        <ResponseField name="proof" type="DecisionProof" required />

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

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

        <ResponseField name="trace" type="RecursiveChatTraceStep[]">
          Full proof trace, when `include_trace` was set.
        </ResponseField>

        <ResponseField name="usage" type="DecisionUsage" required />

        <ResponseField name="verifiable_bundle" type="object">
          A self-contained, INDEPENDENTLY-VERIFIABLE proof bundle for an approved decision: the exact facts and rules plus a `RuleEngine::backward_chain` derivation of the authorization goal, in the `knowledge::ProofBundle` wire format. POST it verbatim to `/v1/proofs/verify` (or check it offline with the dependency-light `proof_check`) to confirm the verdict without trusting this server. Present only when the caller declared an `authorization_goal` AND the rule engine reproduces the proof; absent otherwise (the verdict still stands on its own derivation).
        </ResponseField>

        <ResponseField name="warnings" type="string[]">
          Non-fatal advisories about how the verdict was derived (e.g. the outcome rested on predicate-name inference rather than declared rule effects). Omitted when empty.
        </ResponseField>

        <ResponseField name="x_nsr" type="object" />
      </Expandable>
    </ResponseField>

    <ResponseField name="evidence" type="AnswerEvidence" required>
      <Expandable title="AnswerEvidence">
        <ResponseField name="because" type="string" required>
          Human-readable statement of why, derived from the proof.
        </ResponseField>

        <ResponseField name="cited_rules" type="string[]" required />

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

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

        <ResponseField name="policy_hash" type="string">
          sha256 over the exact policy this answer stands on.
        </ResponseField>

        <ResponseField name="replayable" type="boolean">
          True when every cited rule re-fires from the evidence in this response.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="gaps" type="AnswerGap[]">
      What to go and find out. Each entry, if confirmed, may change the answer.

      <Expandable title="AnswerGap">
        <ResponseField name="fact" type="string" required />

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

    <ResponseField name="reply" type="object">
      <Expandable title="reply">
        <ResponseField name="auto_send" type="boolean" required>
          True only when the macro is approved, fully filled, its tool call fully bound, and the macro itself armed for auto-send. Anything less is a draft for a human.
        </ResponseField>

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

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

        <ResponseField name="missing_slots" type="string[]" required>
          Merge fields with no value supplied. Non-empty blocks sending.
        </ResponseField>

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

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

    <ResponseField name="requires_human" type="string[]">
      Why a human is needed. Empty means none is.
    </ResponseField>

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

    <ResponseField name="tool_call" type="object">
      Emitted, NOT executed — the engine never holds your credentials. Run it against your own systems.
    </ResponseField>

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

<ResponseField name="auto_send_count" type="integer" required />

<ResponseField name="errors" type="BatchAnswerError[]" required>
  Per-item failures by index. One bad ticket never sinks a queue.

  <Expandable title="BatchAnswerError">
    <ResponseField name="error" type="string" required />

    <ResponseField name="index" type="integer" required />

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

<ResponseField name="human_count" type="integer" required />

### Status codes

| Code  | Meaning                                            |
| ----- | -------------------------------------------------- |
| `200` | One answer per ticket                              |
| `401` | Unauthorized — missing or invalid credentials      |
| `403` | Forbidden — the key/token lacks the required scope |
| `429` | Rate limited — see Retry-After / X-RateLimit-Reset |

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://api.nsr.stateset.com/api/v1/answer/batch' \
    --header 'X-API-Key: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
    "items": [
      {
        "context": {},
        "facts": {},
        "include_decision": true,
        "mode": "string",
        "question": "string",
        "rules": [],
        "subject": "string"
      }
    ]
  }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "answers": [
      {
        "auto_send": true,
        "decision": {
          "action": null,
          "confidence": null,
          "decision": null,
          "decision_id": null,
          "dropped_citations": null,
          "evaluated_goal": null,
          "grounding": null,
          "gss_machine": null,
          "plain_explanation": null,
          "proof": null,
          "rationale": null,
          "refusal": null,
          "trace": null,
          "usage": null,
          "verifiable_bundle": null,
          "warnings": null,
          "x_nsr": null
        },
        "evidence": {
          "because": null,
          "cited_rules": null,
          "decision_id": null,
          "grounding": null,
          "policy_hash": null,
          "replayable": null
        },
        "gaps": [],
        "reply": {
          "auto_send": null,
          "macro_id": null,
          "macro_name": null,
          "missing_slots": null,
          "rendered": null,
          "rule_name": null
        },
        "requires_human": [],
        "subject": "string",
        "tool_call": null,
        "verdict": "string"
      }
    ],
    "auto_send_count": 1,
    "errors": [
      {
        "error": "string",
        "index": 1,
        "subject": "string"
      }
    ],
    "human_count": 1
  }
  ```
</ResponseExample>
