> ## Documentation Index
> Fetch the complete documentation index at: https://paperplane-justin-winter-s-projects.vercel.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Build with agents

> Give any AI agent hands on physical mail: MCP in one command, REST in two calls, safe by construction.

paperplane is agent-native the whole way down: an MCP server, a REST API with
deterministic schemas, machine-actionable errors, and a spend-safety model that
makes it reasonable to let an agent mail a real, irreversible, paid object.

## Connect in one command (MCP)

<CodeGroup>
  ```bash Claude Code theme={null}
  claude mcp add --transport http paperplane https://sendpaperplane.com/api/mcp
  ```

  ```bash Claude Desktop / other MCP clients theme={null}
  # Streamable HTTP endpoint — no auth required:
  https://sendpaperplane.com/api/mcp
  ```
</CodeGroup>

Cursor, VS Code/Copilot, Windsurf, Cline, Continue.dev, Gemini CLI, Codex
CLI, and 15+ others all connect to the same URL, each with its own config
shape — see the [MCP server guide](/docs/guides/mcp#connect) for the exact snippet per client
rather than guessing at the field names.

Three tools, one invariant:

| Tool                | Kind      | What it does                                                       |
| ------------------- | --------- | ------------------------------------------------------------------ |
| `quote_letter`      | read      | Prices a letter, returns the all-in price + a `confirmation_token` |
| `send_letter`       | **write** | Mails it. Spends money. Requires the `confirmation_token`          |
| `get_letter_status` | read      | Tracks any order                                                   |

**The invariant: a send is never the first call.** `send_letter` only accepts a
single-use `confirmation_token` minted by `quote_letter`, cryptographically
bound to the recipient, content, mail class, and price. Nothing can change
between the quote your agent (or your user) saw and the letter that gets
mailed — and a replayed token returns `confirmation_used`, not a second letter.

Try it free right now — tell your agent:

> Using the paperplane tools, quote a 1-page certified letter to Property LLC,
> 1 Main St, Richmond VA 23220, then send it in sandbox mode.

Sandbox runs the entire pipeline (validation, address correction, mock
fulfillment, tracking number) with no payment and nothing mailed.

## Or REST, two calls

```bash theme={null}
# 1. Quote → confirmation_token (free, creates nothing)
curl -X POST https://sendpaperplane.com/v1/quotes \
  -H 'Content-Type: application/json' \
  -d '{ "mail_class": "certified", "page_count": 1,
        "to": { "name": "Property LLC", "line1": "1 Main St",
                "city": "Richmond", "state": "VA", "zip": "23220" },
        "text": "Formal demand for return of my security deposit..." }'

# 2. Send (sandbox) — pass the token, add an Idempotency-Key
curl -X POST https://sendpaperplane.com/v1/orders \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: my-agent-run-42' \
  -d '{ "mail_class": "certified", "sandbox": true,
        "confirmation_token": "<from step 1>",
        "to":   { "name": "Property LLC", "line1": "1 Main St",
                  "city": "Richmond", "state": "VA", "zip": "23220" },
        "from": { "name": "Alex Rivera", "line1": "12 Grove Ave",
                  "city": "Richmond", "state": "VA", "zip": "23221" },
        "text": "Formal demand for return of my security deposit..." }'
```

Live mode is the same call without `sandbox` — it returns a `payment_url` for a
human to approve, so an agent can prepare mail it can't silently pay for.

## Or a funded wallet pays directly (x402)

For an agent that holds its own funded crypto wallet rather than a human's
card, `POST /v1/x402/credits` (MCP: `buy_credits`) lets it pay USDC on Base
directly, no human checkout step — settle once, get a prepaid `credit_code`,
spend it with `send_letter`. **Staged**: real, tested code that reports
`x402_not_configured` until a facilitator account is provisioned;
`sandbox: true` works today with no setup. See
[Agent payments (x402)](/docs/guides/agent-payments).

## Why it's safe to wire into an autonomous loop

* **Impossible to double-send.** `Idempotency-Key` replays return the original
  order (`"replayed": true`, same id); a reused `confirmation_token` is
  refused with `confirmation_used`. Retry storms can't mail twice or charge twice.
* **No silent spend.** Every paid send requires either an explicit
  human-approved `payment_url` or a prepaid `credit_code` — plus the
  confirmation token proving the price was seen.
* **Errors are recovery playbooks.** Every failure returns
  `{ status, code, reason, next[] }` — `next` is what a support human would
  say, machine-readable. Full catalogue: [Error contract](/docs/guides/errors).
* **Money comes back on its own.** If fulfillment fails after capture, an
  hourly reconcile loop refunds automatically — recovery is a system property.
* **Deterministic surface.** The [OpenAPI 3.1 spec](https://sendpaperplane.com/v1/openapi.json)
  is generated from the same Zod schemas the server parses with — the spec
  can't drift from reality. `llms.txt` lives at
  [`/llms.txt`](https://sendpaperplane.com/llms.txt); the agent card at
  [`/.well-known/agent.json`](https://sendpaperplane.com/.well-known/agent.json).

## Guardrails in action

The bullets above are claims. Here's what it actually looks like when the
system says no — the same guardrail firing you'd expect a voice-agent
platform to log as "Request blocked by guardrail," except ours is a
machine-readable envelope your agent can act on, not just a log line.

**An agent replays a `confirmation_token` that already mailed a letter:**

```json 409 Conflict theme={null}
{ "status": "action_required", "code": "confirmation_used",
  "reason": "This confirmation_token was already used to send a letter. Each quote authorises exactly one letter.",
  "next": ["Quote again — POST /v1/quotes (MCP: quote_letter) — to authorise another letter."] }
```

**An agent (or a bug) sends a tampered or fabricated token:**

```json 400 Bad Request theme={null}
{ "status": "action_required", "code": "confirmation_malformed",
  "reason": "confirmation_token is not a paperplane quote token.",
  "next": ["Quote first: POST /v1/quotes (MCP: quote_letter) with the exact parameters you intend to send, then pass the confirmation_token it returns."] }
```

Both are captured verbatim from the live [agent benchmark](/docs/benchmark) run,
not hand-written examples — `send_letter` never mails and no payment is
captured on a blocked call. `next` is the recovery step, not decoration: the
agent reads it and knows what to do without a human in the loop. Full
catalogue of every code the spend-safety gate can return: [Error
contract](/docs/guides/errors#confirmation-errors-action_required-the-spend-safety-gate).

## Proof

We publish a reproducible transcript of an agent completing
quote → send → track: **3 REST calls (2 MCP tool calls), zero schema retries**.
See the [agent benchmark](/docs/benchmark).
