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

# Approve a quote

> Explicitly approve the exact mailpiece and price of a quote

## Overview

Records a person's approval of one quote at one price. Repeat the `input_hash` and `total_usdc` the quote returned: a changed piece or price is refused. Nothing is charged yet. Returns the `approval_id` that [Send](https://docs.oneshotagent.com/api-reference/physical-mail/send.md) needs with the `quote_id`. Free.

Call this from the approver's handler after they have seen `preview.url` and `total_usdc`, never automatically after a preview. Approving the same quote twice returns the same `approval_id`.

## Authentication

`X-Agent-ID` plus a signed `x-agent-proof` with `scope: "write"`, or an access token. See [proof authentication](https://docs.oneshotagent.com/sdk/overview.md#read-authentication). 60 requests a minute per agent.

## Request Body

**quote\_id** `string` *required*

Quote ID from the preview

**input\_hash** `string` *required*

The `input_hash` the quote returned (64 hex characters)

**total\_usdc** `string` *required*

The `total_usdc` the quote returned, as a decimal string

**approved** `boolean` *required*

Must be `true`: an explicit approval of this piece at this price

## Response

**approval\_id** `string`

Approval ID to send with the quote

**quote\_id** `string`

The approved quote

```bash cURL theme={null}
curl -X POST https://win.oneshotagent.com/v1/tools/physical-mail/approve \
  -H "Content-Type: application/json" \
  -H "X-Agent-ID: 0xYourWalletAddress" \
  -H "x-agent-proof: <base64 signed proof, scope=write>" \
  -d '{
    "quote_id": "00000000-0000-4000-8000-000000000000",
    "input_hash": "<the quote'"'"'s input_hash>",
    "total_usdc": "<the quote'"'"'s total_usdc>",
    "approved": true
  }'
```

```typescript SDK theme={null}
import { OneShot } from "@oneshot-agent/sdk";

const agent = new OneShot({ privateKey: process.env.AGENT_PRIVATE_KEY });

const approval = await agent.physicalMail.approve({
  quote_id: quote.quote_id,
  input_hash: quote.input_hash,
  total_usdc: quote.total_usdc!,
  approved: true,
});
```

```python Python theme={null}
approval = client.physical_mail.approve(
    quote_id=quote["quote_id"],
    input_hash=quote["input_hash"],
    total_usdc=quote["total_usdc"],
    approved=True,
)
```

```json Response theme={null}
{
  "approval_id": "00000000-0000-4000-8000-000000000000",
  "quote_id": "00000000-0000-4000-8000-000000000000"
}
```

```json Quote Changed or Expired (409) theme={null}
{
  "error": "quote_changed_or_expired"
}
```

## Errors

| Code | When |
| - | - |
| `400 invalid_input` | `approved` is not `true`, or a field has the wrong shape |
| `409 quote_changed_or_expired` | The quote expired, is still rendering, or `input_hash` or `total_usdc` differ from the quote |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.