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

# x402 Agent

> Open-source Fireblocks-powered agent that automatically pays for x402-protected resources — available as an MCP server and a CLI.

The x402 Agent is a TypeScript client for the **x402 payment protocol (v2)** that gives any autonomous agent the ability to pay for HTTP 402-protected resources using a Fireblocks vault. It handles the full payment loop: detecting the `402 Payment Required` response, constructing and signing the EIP-712 payment payload via Fireblocks, and retrying the original request with proof of payment. Gasless signing happens off-chain — the agent never submits an on-chain transaction itself.

Source: [github.com/fireblocks/x402-agent](https://github.com/fireblocks/x402-agent)

Ships in two forms: an **MCP server** for Claude Desktop, Cursor, and other MCP clients, and a **CLI** for scripting and testing payment flows from the terminal. Before production use, combine the four security layers in [Secure deployment](#secure-deployment) so the agent can only spend what you explicitly allow.

## Requirements

* Node.js 18+
* Fireblocks API account with a vault configured
* Sufficient token balance on the target network (for example, USDC on Base)

## How it works

### Payment sequence

```
Agent  ──GET /resource──►  Merchant server
                            │
                      ◄─── 402 + PaymentRequired body

Agent constructs EIP-712 payload, signs via Fireblocks,
retries with PAYMENT-SIGNATURE header:

Agent  ──GET /resource──►  Merchant server
  PAYMENT-SIGNATURE: <base64 payload>
                            │
                      ◄─── 200 + PAYMENT-RESPONSE header
                                 (tx hash, network, payer)
```

**The agent never calls the facilitator directly.** It sends signed payment headers to the merchant server; the merchant's x402 middleware calls the facilitator to verify and settle on-chain.

1. **Initial request** — Agent sends GET to the resource server.
2. **402 Payment Required** — Resource server returns a `PaymentRequired` JSON body with `accepts[]` payment options.
3. *(Optional)* **Integrity check** — Agent verifies the envelope against the facilitator's `did:web` key (see [Payment Instruction Integrity](#payment-instruction-integrity)).
4. **Select mechanism** — Agent picks the first supported `accepts[]` entry (preference: `eip3009` → `permit2`; overridable via `MECHANISM`).
5. **Build and sign EIP-712** — Agent constructs typed data locally and signs via Fireblocks.
6. **Retry with signature** — Agent resends the GET with a `PAYMENT-SIGNATURE` header. Resource server settles the payment and returns the resource with a `PAYMENT-RESPONSE` receipt header.

Two round-trips total: the initial 402, then the retry with signature.

### Transfer mechanisms

| Mechanism  | Description                                                             |
| ---------- | ----------------------------------------------------------------------- |
| `eip-3009` | `TransferWithAuthorization` — native for USDC and other ERC-3009 tokens |
| `permit2`  | Uniswap Permit2 `PermitWitnessTransferFrom` — universal ERC-20 fallback |

ERC-7710 delegation is not supported — Fireblocks cannot sign delegation payloads.

Permit2 supports two schemes, chosen by the server in the 402 `accepts[].scheme` field:

* **`exact`** — authorizes the merchant to pull **exactly** the amount in the 402 body. Recommended default.
* **`upto`** — authorizes the merchant to pull **up to** the amount in the 402 body (the actual debit is decided by the facilitator at settlement time). Useful for variable-cost endpoints, but gives the merchant discretion within the cap. Pair with tighter Policy Engine rules if you use it.

### Payment Instruction Integrity

The agent can verify that the `PaymentRequired` body wasn't tampered with between the facilitator and the client.

* The facilitator emits a base64url-encoded envelope on `PaymentRequired.integrity` (also mirrored on the `X-402-Integrity` response header).
* The envelope is signed ES256 (P-256) and the key is resolved via `did:web`.
* Canonical bytes: `SHA-256( JCS({x402Version, accepts}) || "\n" || iat || "\n" || exp )`.
* `resource.url`, `error`, and `extensions` are intentionally excluded from the signed slice.

Set `VERIFY_INTEGRITY=true` for best-effort verification (warns if missing or invalid), or `REQUIRE_INTEGRITY=true` to abort when the envelope is absent or invalid. The `require_integrity` parameter on `x402_get_and_pay` enforces integrity for a single call and cannot relax env settings.

## Get started

```bash theme={"system"}
git clone https://github.com/fireblocks/x402-agent
cd x402-agent
npm install
cp .env.example .env
# Edit .env with your Fireblocks credentials
npm run build
```

Place your Fireblocks private key at the path referenced by `FIREBLOCKS_PRIVATE_KEY_PATH`.

| Variable                            | Description                                                                                      |
| ----------------------------------- | ------------------------------------------------------------------------------------------------ |
| `FIREBLOCKS_API_KEY`                | Fireblocks API key UUID                                                                          |
| `FIREBLOCKS_VAULT_ACCOUNT_ID`       | Vault account to pay from                                                                        |
| `FIREBLOCKS_PRIVATE_KEY_PATH`       | Path to Fireblocks RSA private key                                                               |
| `MECHANISM`                         | Force a transfer mechanism: `eip3009` or `permit2` (default: `eip3009`, falls back to `permit2`) |
| `VERIFY_INTEGRITY`                  | `true` to verify integrity envelopes when present                                                |
| `REQUIRE_INTEGRITY`                 | `true` to require a valid integrity envelope on every call                                       |
| `ALLOWED_MERCHANT_HOSTS`            | Comma-separated allowed hosts; agent refuses any URL whose host isn't listed                     |
| `REQUIRE_CONFIRM`                   | When `true`, MCP pay-tools refuse to pay unless called with `confirmed=true`                     |
| `ALLOW_LOCAL_TARGETS`               | When `true`, permit private / loopback URLs (local dev only; leave unset in production)          |
| `FIREBLOCKS_BASE_URL_ALLOWED_HOSTS` | Comma-separated additional Fireblocks API hostnames to trust beyond `*.fireblocks.io`            |

## Usage

### MCP server

The MCP server exposes four tools:

| Tool                    | Description                                                            |
| ----------------------- | ---------------------------------------------------------------------- |
| `x402_get_and_pay`      | Fetch a URL, automatically pay if 402 is returned, return the resource |
| `x402_get_payment_info` | Inspect payment requirements for a URL without paying                  |
| `http_get`              | Generic GET (routes 402 responses to suggest x402 tools)               |
| `http_post`             | Generic POST                                                           |

Start the server (stdio):

```bash theme={"system"}
npm start
```

#### Connect to Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) — use **absolute paths**. Windows config lives at `%APPDATA%\Claude\claude_desktop_config.json`; Linux at `~/.config/Claude/claude_desktop_config.json`.

```json theme={"system"}
{
  "mcpServers": {
    "x402-payment": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/x402-agent/dist/mcp-server.js"],
      "env": {
        "FIREBLOCKS_API_KEY": "<api-key>",
        "FIREBLOCKS_VAULT_ACCOUNT_ID": "<vault-id>",
        "FIREBLOCKS_PRIVATE_KEY_PATH": "/ABSOLUTE/PATH/TO/x402-agent/.secrets/your-key.key",
        "VERIFY_INTEGRITY": "true"
      }
    }
  }
}
```

Restart Claude Desktop to pick up the server.

#### Test with MCP Inspector

```bash theme={"system"}
npx @modelcontextprotocol/inspector node dist/mcp-server.js
```

#### Example prompts

```
Use x402_get_and_pay to fetch http://localhost:3010/get-gold
```

```
Use x402_get_payment_info to check what payment is required for http://localhost:3010/get-gold
```

#### x402\_get\_and\_pay options

| Parameter           | Type                   | Default  | Description                                                           |
| ------------------- | ---------------------- | -------- | --------------------------------------------------------------------- |
| `url`               | string                 | required | URL to fetch                                                          |
| `auto_pay`          | boolean                | `true`   | Complete payment automatically                                        |
| `selection`         | `"auto"` \| `"manual"` | `"auto"` | Option selection mode                                                 |
| `option_index`      | number                 | —        | Explicitly pick a payment option by index                             |
| `check_balance`     | boolean                | `true`   | Query vault balance before picking an option                          |
| `require_integrity` | boolean                | `false`  | Abort if Payment Instruction Integrity envelope is missing or invalid |

**Auto selection** picks the best-funded option in preference order: `eip-3009` → `permit2`. Set `MECHANISM=permit2` to force a specific mechanism.

**Manual selection** returns the full list of funded options when more than one is available. Re-call with `option_index=<N>` to complete the payment.

### CLI

Run a one-shot payment from the terminal:

```bash theme={"system"}
npm run dev:cli
```

Or invoke directly with `npx` (no global install):

```bash theme={"system"}
npx tsx src/index.ts
```

For a production build:

```bash theme={"system"}
node dist/index.js
```

## Secure deployment

The agent never custodies keys — it asks Fireblocks to sign. Combine four controls so the agent can only spend what you've explicitly allowed, even if the host running it is compromised or an LLM driving it goes off-rails.

### Provision a scoped Fireblocks API user

Grant only the minimum permissions the agent actually needs. Create a dedicated API user in the Fireblocks Console — don't reuse a workspace-admin key. See the official Fireblocks guides on [creating a new API user](https://support.fireblocks.io/hc/en-us/articles/4407823826194-Adding-new-API-Users) and [best practices for choosing user roles](https://support.fireblocks.io/hc/en-us/articles/5254222799900-Best-practices-for-choosing-user-roles).

* **Role:** *Signer* (or any role limited to `Create Transaction` / signing operations). No policy edit, no user management, no workspace admin.
* **Vault scope:** Restrict to a single dedicated vault used **only** for x402 spend. Keep its balance small — top it up as needed rather than parking your treasury there.
* **IP allowlist:** Add the machine(s) that will run the agent.
* **CSR / API key fingerprint:** Record both so you can rotate confidently.

### Store the API credentials securely

The Fireblocks API key and its private signing key file are highly sensitive credentials.

<Warning>
  **API credentials must never be shared publicly** — not in commits, not in chat transcripts, not in screenshots.
</Warning>

Store the private key file with restricted access (`chmod 600`), preferably outside the repo, and never bake it into a container image. The agent reads `FIREBLOCKS_API_KEY` (the API user ID, a UUID) and `FIREBLOCKS_PRIVATE_KEY_PATH` (path to the API user's private signing key). Treat both like production secrets.

| Environment        | Storage                                                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| Local dev          | `.env` (gitignored) + key file in `.secrets/` (gitignored). Restrict file mode: `chmod 600 .secrets/*.key .env`.                            |
| CI                 | Secrets injected as masked variables by the CI provider (GitHub Actions encrypted secrets, GitLab masked variables, etc.). Never echo them. |
| Server / container | Secrets manager (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, HashiCorp Vault) mounted at runtime — not baked into the image.  |
| Kubernetes         | `Secret` resource mounted as a file, ideally backed by External Secrets Operator pulling from a secrets manager.                            |

Never commit `.env`, `.secrets/`, the API user PEM, or the rendered `.mcp.json` (the project's `.gitignore` already excludes these — keep it that way).

### Enforce human-in-the-loop signing via the Policy Engine

This is the strongest control and the one most worth setting up. The [Fireblocks Policy Engine (TAP)](/docs/set-transaction-authorization-policy) gates every signing request at the Fireblocks side — not in agent code — so it survives a compromise of the agent host or its API key. See the [Fireblocks rule parameters guide](https://support.fireblocks.io/hc/en-us/articles/7365877039004-Rule-parameters) for the full schema.

Recommended rules for an x402 agent vault:

* **Whitelist destinations.** Allow only the asset types and recipient addresses you expect (for example, USDC on Base to specific facilitator settlement contracts). Deny everything else.
* **Per-tx amount cap** matched to a single x402 micropayment (for example, ≤ 1 USDC).
* **Per-period velocity cap** (hourly / daily) matched to the agent's autonomous budget.
* **Designate a manual signer / approver above a threshold.** Configure the policy to require a designated approver for any transaction above your auto-sign threshold; approvals are pushed to the Fireblocks mobile app and enforced cryptographically by the policy, not by trust in the agent code. This is the canonical Fireblocks human-in-the-loop pattern (same approach recommended by the [`fireblocks-mcp`](https://github.com/fireblocks/fireblocks-mcp) server).
* **2-eyes for any change to the policy itself** so a compromised admin can't widen the rules silently.

### Constrain the agent at the application layer

These are defense-in-depth — the Policy Engine is still the source of truth. Useful for autonomous-agent flows where the URL or LLM context can't be trusted:

* **Fireblocks base-URL allowlist (on by default).** `FIREBLOCKS_BASE_URL` must be HTTPS under `*.fireblocks.io`. The Fireblocks SDK does not validate this URL itself, and its signed JWT only binds the request *path* — not the host — so an attacker who tampers with `FIREBLOCKS_BASE_URL` (via a poisoned `.env`, shell compromise, or CI env injection) could MITM the API channel and replay signed requests against the real Fireblocks within the 55s JWT validity window. For private / alternative endpoints, set `FIREBLOCKS_BASE_URL_ALLOWED_HOSTS=host1,host2` with the exact additional hostnames you trust.
* **SSRF guard (on by default).** Every outbound URL is validated before any request is made: non-`http`/`https` schemes are rejected, and IP literals or DNS results in private / loopback / link-local / metadata-range space (including `169.254.169.254`, GCP `metadata.google.internal`, Alibaba `100.100.100.200`, IPv6 `fc00::/7` / `fe80::/10` / `::1`) are blocked. HTTP redirects (`maxRedirects: 0`) are disabled so a 3xx can't bypass the upfront check. Set `ALLOW_LOCAL_TARGETS=true` only for local development.
* **`ALLOWED_MERCHANT_HOSTS`** — agent refuses any request whose host isn't in the comma-separated list. Recommended whenever the URL can come from an LLM or external feed.
* **`REQUIRE_CONFIRM=true`** (MCP only) — `x402_get_and_pay` returns a payment preview and refuses to sign until called again with `confirmed=true`.
* **`REQUIRE_INTEGRITY=true`** — refuse to sign 402 responses that fail Payment Instruction Integrity verification.
* Prefer Permit2 **`exact`** over **`upto`** unless you specifically need variable-cost semantics.

## Troubleshooting

| Issue                                            | Cause                                                          | Solution                                                                                            |
| ------------------------------------------------ | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `no supported payment mechanism in accepts[]`    | Server only offered ERC-7710 or another unsupported mechanism  | Ensure the server offers `eip3009` or `permit2`                                                     |
| `integrity check failed`                         | Envelope expired, `did:web` unresolvable, or signature invalid | Check facilitator clock skew and DID doc availability; relax to `VERIFY_INTEGRITY` if not enforcing |
| `ERROR_TYPED_MESSAGE_TO_PROTECTED_7702_CONTRACT` | Fireblocks policy blocked the signature                        | Add a Typed Message Policy in Fireblocks that allows this typed data                                |
| Payment expired                                  | Too slow between 402 and retry                                 | Re-request to get a fresh 402; reduce Fireblocks signing latency                                    |
| Invalid signature                                | Wrong domain/types/message                                     | Verify `eip712_name` / `version` from `accepts[].extra`, and that chainId matches                   |

## References

* [EIP-3009: Transfer With Authorization](https://eips.ethereum.org/EIPS/eip-3009)
* [EIP-712: Typed structured data hashing and signing](https://eips.ethereum.org/EIPS/eip-712)
* [Permit2](https://github.com/Uniswap/permit2)
* [Fireblocks Web3 Provider](https://github.com/fireblocks/fireblocks-web3-provider)
* [Repository source layout](https://github.com/fireblocks/x402-agent) — `src/index.ts` (CLI), `src/mcp-server.ts` (MCP), `src/HttpX402Service.ts` (payment logic), `src/FireblocksService.ts` (Web3 provider), `src/IntegrityVerifier.ts` (integrity checks)
