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

# Approving answers

> Every expert answer becomes a pending proposal that a human reviews before it reaches a consumer. Approve or reject from the web UI or the CLI.

Human review is the safety layer between an expert's reply and your system of record. When an expert answers, ShoulderTap structures the reply into a **proposal** and places it in the approval queue as `pending`. Nothing is delivered to a consumer until a person accepts it — the raw answer, the structured form, and the provenance are all shown so a reviewer can catch a wrong or poisoned answer before it's written back.

<Note>
  The one exception is a consumer that registered with `auto_accept: true`, which delivers without review. It's off by default precisely because skipping review is a real write-back-poisoning risk. See [Consumers](/consumers/overview).
</Note>

## The web approval UI

`shtap serve` serves a single-page approval queue at the server root, `http://localhost:8776/`. It lists pending proposals and lets a reviewer accept or reject each one. The page prompts for the bearer token so it can call the API on your behalf.

## From the CLI

<Steps>
  <Step title="List pending proposals">
    ```bash theme={null}
    shtap queue
    ```

    Prints each pending proposal with its id, the originating question, and the expert's answer. If nothing is pending, it prints `Nothing pending`.
  </Step>

  <Step title="Accept a proposal">
    ```bash theme={null}
    shtap accept prop_01J...
    ```

    Marks the proposal accepted, records who decided it, delivers `on_proposal_accepted` to every subscribed consumer, and notifies the expert that their answer was accepted and attributed to them. `--decided-by` defaults to your OS username.
  </Step>

  <Step title="Reject a proposal">
    ```bash theme={null}
    shtap reject prop_01J... --reason "not accurate"
    ```

    Marks the proposal rejected and delivers `on_proposal_rejected` (with the reason) to the consumer. `--reason` is required; `--decided-by` defaults to your OS username.
  </Step>
</Steps>

## What acceptance does

Accepting a proposal:

* Sets the proposal's status to `accepted` and the request's status to `accepted`.
* Delivers the accepted proposal to **all** subscribed consumers (including any attached by deduplication) via `on_proposal_accepted` — this is where your consumer writes the answer to a system of record.
* Sends the expert a notification that their answer was accepted, closing the loop on the attribution promise.

Deciding a proposal that's already been accepted or rejected is a no-op.

## Over the API

The same actions are available on the HTTP API:

* `GET /proposals?status=pending` — the queue. See the [Proposals endpoint](/api/proposals).
* `POST /proposals/{id}/accept` with `{ "decided_by": "alice" }`.
* `POST /proposals/{id}/reject` with `{ "decided_by": "alice", "reason": "not accurate" }`.

You can trace every step a request took — received, asked, escalated, replied, decided — with `GET /audit?request_id=...`. See the [Audit endpoint](/api/audit).
