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

# Proposals

> List pending proposals and accept or reject them over the ShoulderTap HTTP API — the approval queue.

Proposals are expert answers awaiting human review. These endpoints back the [approval queue](/run/approvals).

## List pending proposals

<code>GET /api/v1/proposals?status=pending</code>

```bash theme={null}
curl "http://localhost:8776/api/v1/proposals?status=pending" \
  -H "Authorization: Bearer $SHOULDERTAP_API_TOKEN"
```

Returns the pending [ContextProposals](/api/contracts). Each carries its `id`, its `request_id`, the expert's `answer`, the `structured` form, `confidence`, and `provenance`.

<ParamField query="status" type="pending">
  Currently only `pending` is supported — the queue of proposals awaiting a decision.
</ParamField>

## Accept a proposal

<code>POST /api/v1/proposals/\{id}/accept</code>

Approves the answer and delivers it to every subscribed consumer via `on_proposal_accepted`.

```bash theme={null}
curl -X POST http://localhost:8776/api/v1/proposals/prop_01J.../accept \
  -H "Authorization: Bearer $SHOULDERTAP_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decided_by": "alice"}'
```

<ParamField body="decided_by" type="string" required>
  Who approved the proposal.
</ParamField>

<ParamField body="note" type="string">
  An optional note recorded with the decision.
</ParamField>

Returns the updated proposal. Accepting also sets the request's status to `accepted` and notifies the expert that their answer was accepted. An unknown id returns `404`; deciding an already-decided proposal is a no-op.

## Reject a proposal

<code>POST /api/v1/proposals/\{id}/reject</code>

```bash theme={null}
curl -X POST http://localhost:8776/api/v1/proposals/prop_01J.../reject \
  -H "Authorization: Bearer $SHOULDERTAP_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"decided_by": "alice", "reason": "not accurate"}'
```

<ParamField body="decided_by" type="string" required>
  Who rejected the proposal.
</ParamField>

<ParamField body="reason" type="string" required>
  Why it was rejected. Delivered to the consumer with `on_proposal_rejected`.
</ParamField>

Returns the updated proposal and sets the request's status to `rejected`.
