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

# Approvals

> Review and action pending transactions queued by the auto-approve-threshold policy.

# Approvals

When a transaction value exceeds the `auto-approve-threshold` policy, Steward queues it for human review instead of signing immediately. The approvals API lets you list, inspect, approve, and deny these pending transactions.

**Base path:** `/approvals`\
**Auth:** Tenant-level (`X-Steward-Key`)

***

## How Approvals Work

1. Agent submits a sign request via SDK or REST API
2. Policy engine evaluates all rules — hard policies (`spending-limit`, etc.) must pass
3. If `auto-approve-threshold` is set and the value exceeds it, the transaction is **queued** (HTTP 202)
4. Steward fires a `tx.pending` webhook event (if configured)
5. A human reviews via the API, SDK, or `<ApprovalQueue>` React component
6. On approval: Steward signs the transaction and optionally broadcasts
7. On denial: the transaction is marked rejected and a `tx.denied` webhook fires

***

## List Pending Approvals

```bash theme={null}
GET /approvals?status=pending&limit=50&offset=0
```

```bash theme={null}
curl https://api.steward.fi/approvals \
  -H "X-Steward-Key: your-tenant-key"
```

**Query params:**

| Param    | Default   | Description                                                   |
| -------- | --------- | ------------------------------------------------------------- |
| `status` | `pending` | Filter by status: `pending`, `approved`, `rejected`, or `all` |
| `limit`  | `50`      | Max results (max: 200)                                        |
| `offset` | `0`       | Pagination offset                                             |

**Response:**

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "appr_550e8400-...",
      "txId": "tx_660f9500-...",
      "agentId": "trading-bot-1",
      "agentName": "Trading Bot Alpha",
      "status": "pending",
      "requestedAt": "2026-03-27T14:00:00Z",
      "resolvedAt": null,
      "resolvedBy": null,
      "toAddress": "0xUniswapRouter...",
      "value": "2000000000000000000",
      "chainId": 8453,
      "txStatus": "pending_approval"
    }
  ]
}
```

***

## Approval Stats

```bash theme={null}
GET /approvals/stats
```

Returns aggregate counts across all agents in the tenant:

```json theme={null}
{
  "ok": true,
  "data": {
    "pending": 3,
    "approved": 142,
    "rejected": 8,
    "total": 153,
    "avgWaitSeconds": 340
  }
}
```

***

## Approve a Transaction

```bash theme={null}
POST /approvals/:id/approve
```

```bash theme={null}
curl -X POST https://api.steward.fi/approvals/appr_550e8400-.../approve \
  -H "X-Steward-Key: your-tenant-key"
```

Steward immediately signs the transaction. If `broadcast: true` was set in the original sign request, the transaction is also broadcast to the chain.

**Response:**

```json theme={null}
{
  "ok": true,
  "data": {
    "approvalId": "appr_550e8400-...",
    "status": "approved",
    "txHash": "0xabc123...",
    "resolvedAt": "2026-03-27T14:05:00Z"
  }
}
```

***

## Deny a Transaction

```bash theme={null}
POST /approvals/:id/deny
```

```bash theme={null}
curl -X POST https://api.steward.fi/approvals/appr_550e8400-.../deny \
  -H "X-Steward-Key: your-tenant-key" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Amount too large for current market conditions" }'
```

The `reason` field is optional but recommended — it's included in the `tx.denied` webhook payload.

**Response:**

```json theme={null}
{
  "ok": true,
  "data": {
    "approvalId": "appr_550e8400-...",
    "status": "rejected",
    "resolvedAt": "2026-03-27T14:05:00Z",
    "resolvedBy": "manual"
  }
}
```

***

## Auto-Expiry

Approvals auto-expire after the duration set in the tenant's `approvalConfig.autoExpireSeconds`. Once expired, the transaction cannot be approved and the agent must resubmit.

Default: `86400` (24 hours). Set to `0` to disable auto-expiry.

***

## Setting Up the Auto-Approve Threshold

Configure the threshold in your agent's policy set:

```typescript theme={null}
await client.setPolicies("trading-bot-1", [
  // Other policies...
  {
    id: "auto-threshold",
    type: "auto-approve-threshold",
    enabled: true,
    config: {
      threshold: "10000000000000000", // 0.01 ETH — auto-sign below, queue above
    },
  },
]);
```

Transactions **at or below** the threshold are signed immediately. Transactions **above** the threshold are queued.

<Note>
  The `auto-approve-threshold` policy is a soft gate — it never hard-rejects. But hard policies (`spending-limit`, `approved-addresses`, etc.) are still evaluated first. A transaction can be both blocked by a hard policy AND above the threshold; it will be rejected, not queued.
</Note>

***

## Using the React Component

The `<ApprovalQueue>` component from `@stwd/react` provides a ready-made UI for reviewing pending transactions:

```tsx theme={null}
import { StewardProvider, ApprovalQueue } from "@stwd/react";

function AdminDashboard({ agentId }) {
  return (
    <StewardProvider client={client} agentId={agentId}>
      <ApprovalQueue
        pollInterval={5000}
        onApprove={(id) => console.log("Approved:", id)}
        onDeny={(id, reason) => console.log("Denied:", id, reason)}
      />
    </StewardProvider>
  );
}
```

***

## Webhook Integration

Configure a `tx.pending` webhook to get notified when transactions need review:

```typescript theme={null}
// Register webhook
await fetch("https://api.steward.fi/webhooks", {
  method: "POST",
  headers: { "X-Steward-Key": apiKey, "Content-Type": "application/json" },
  body: JSON.stringify({
    url: "https://your-app.com/webhooks/steward",
    events: ["tx.pending"],
  }),
});
```

Your webhook handler receives:

```json theme={null}
{
  "event": "tx.pending",
  "agentId": "trading-bot-1",
  "data": {
    "approvalId": "appr_...",
    "to": "0x...",
    "value": "2000000000000000000",
    "chainId": 8453
  }
}
```

Then approve or deny via the REST API from your backend.

***

## Related

* [Webhooks](/api-reference/webhooks) — Subscribe to approval events
* [Tenant Config](/api-reference/tenant-config) — Configure `approvalConfig` settings
* [React Components](/sdk/react-components) — `<ApprovalQueue>` UI component
* [Policy Engine](/concepts/policy-engine) — How `auto-approve-threshold` works
