What the wallet tool is
A Pydantic AI wallet is a reusable tool that gives an agent the ability to pay. The agent calls it with a target, and the tool, through a small local proxy, settles any 402 in USDC on Base and returns the result. The agent gets a wallet the way it gets any capability in Pydantic AI: as a tool attached to it, called when a task needs to pay.
There is no Blockchain0x Pydantic AI package. The wallet tool is a pattern you build from @blockchain0x/node and @blockchain0x/x402, calling a Node proxy because the x402 client is Node-only. This page is the focused artifact; for the broad integration overview see pydantic-ai-payments, and for the task walkthrough see how-to-add-payments-to-pydantic-ai-agent. The payment API product page is the reference.
Build it as a standalone Tool
The reusable shape in Pydantic AI is a standalone Tool object, not an inline @agent.tool bound to one agent. Define the function once, wrap it in a Tool, and you can pass it to any number of agents via tools=[].
import requests
from pydantic_ai import RunContext, Tool
from dataclasses import dataclass
@dataclass
class WalletDeps:
proxy_url: str # this agent's wallet proxy, e.g. "http://127.0.0.1:8787"
def pay_and_fetch(ctx: RunContext[WalletDeps], url: str) -> str:
"""Fetch a URL, paying in USDC if it requires payment. Returns the body."""
res = requests.post(ctx.deps.proxy_url, json={"url": url}, timeout=30)
return res.text if res.status_code == 200 else f"Failed: {res.status_code}"
wallet_tool = Tool(pay_and_fetch, takes_ctx=True)Now wallet_tool is a reusable object. Pass it to an agent with Agent("openai:gpt-4o", deps_type=WalletDeps, tools=[wallet_tool]), run with WalletDeps(proxy_url=...), and the agent can pay. That is the wallet tool: one Tool, attachable anywhere.
One tool, many agents, many wallets
The standalone Tool plus typed deps is what makes the wallet reusable across a fleet without copying code. The same wallet_tool object goes on every agent that should pay, and the deps decide which wallet each run uses.
researcher = Agent("openai:gpt-4o", deps_type=WalletDeps, tools=[wallet_tool])
writer = Agent("openai:gpt-4o", deps_type=WalletDeps, tools=[wallet_tool])
researcher.run_sync("...", deps=WalletDeps(proxy_url="http://127.0.0.1:8787")) # researcher's wallet
writer.run_sync("...", deps=WalletDeps(proxy_url="http://127.0.0.1:8788")) # writer's walletTwo agents, one shared tool object, two wallets selected by deps. Run one proxy per wallet on its own port with that wallet's key, and the dashboard attributes spend per agent while a compromised agent can only spend its own balance. Shared code, separate accounts, expressed the Pydantic AI way through dependencies rather than duplicated tools.
A fixed-wallet variant
When an agent always uses one wallet and you do not need per-run selection, you can skip deps and use a tool_plain, which takes no context. This is the simpler artifact for a single-agent, single-wallet service.
def pay_and_fetch_fixed(url: str) -> str:
"""Fetch a URL, paying in USDC if required."""
res = requests.post("http://127.0.0.1:8787", json={"url": url}, timeout=30)
return res.text if res.status_code == 200 else f"Failed: {res.status_code}"
fixed_tool = Tool(pay_and_fetch_fixed, takes_ctx=False)Use the deps form when wallets vary per agent or per run, and the fixed form when one agent owns one wallet for its lifetime. Both are the same pattern; the difference is only whether the proxy address comes from deps or is baked in.
Keep the surface small
Whichever form you build, keep the tool's surface to one obvious operation: pay-by-calling. Give it a URL and it returns the body, having settled any payment. That single operation covers the common case, an agent paying for data, an API, or another agent, and it is enough for almost every use.
Resist adding an open-ended "send payment to an arbitrary address" operation. It is a far larger attack surface than pay-for-what-you-call, and the wallet's spend limit, set in the dashboard, already bounds what any form of the tool can spend, so the tool does not need to enforce budgets itself. A small, predictable wallet tool is easier for the model to use correctly and easier for you to reason about; let the spend limit be the backstop and keep the tool to what the agent genuinely needs.
Return a typed result, not a blob
Because Pydantic AI is about typed outputs, the wallet tool is a good place to validate the data you just paid for rather than returning a raw string. When the paid response has a known shape, parse it into a Pydantic model inside the tool and return that; validation then catches a malformed or surprising payload before it reaches the model's reasoning, and you spent real money on that response, so catching a bad one early matters.
from pydantic import BaseModel
class Quote(BaseModel):
symbol: str
price: float
def pay_for_quote(ctx: RunContext[WalletDeps], url: str) -> Quote:
"""Fetch a paid price quote, validated."""
res = requests.post(ctx.deps.proxy_url, json={"url": url}, timeout=30)
return Quote.model_validate_json(res.text)This keeps the generic pay_and_fetch for arbitrary URLs and adds a typed tool where the shape is known, which is the Pydantic AI idiom: pay, validate, then reason. Use the generic tool for exploration and a typed one for the sources you call often enough to model. The two coexist on the same agent, and the model picks whichever the task needs, so you do not have to choose one approach for the whole agent.
Compatibility
Because the wallet tool is an ordinary Tool, it works across Pydantic AI's surfaces.
| Pydantic AI surface | Works? | Notes |
|---|---|---|
Standalone Tool in tools=[] |
Yes | Reusable across agents |
takes_ctx=True with typed deps |
Yes | Per-agent wallet via RunContext |
takes_ctx=False (tool_plain) |
Yes | Fixed-wallet variant |
run_sync / run / streaming |
Yes | The tool runs inside the agent's tool call |
| Payment client language | Node | The proxy bridges Python Pydantic AI to the Node x402 client |
When to use it
Reach for the wallet tool when agents need to pay for what they call and you want that capability as one reusable unit rather than per-tool glue. It fits when several agents share the same paying behavior, since you define the Tool once and bind wallets through deps, and when payment should be a capability the model can invoke deliberately.
It is the wrong shape when only one specific tool should ever pay (wrap that tool's own call through the proxy instead) or when the agent is purely internal with no paid calls. Match it to whether paying is a general capability the agents need or a one-off behavior of a single tool.
Pricing
The tool is free; you build it from open packages. What you pay is the wallet platform fee per agent on the pricing page: Free is $0 per agent per month at a 5% transaction fee, Pro is $9 at 2%, and Business is $29 at 1%. Per-agent pricing means each agent that transacts through the tool is billed on its own wallet, so a fleet where only some agents pay only incurs fees for those agents.
What to ship today
Define pay_and_fetch as a standalone Tool, attach it to an agent with tools=[], start a proxy with a sk_test_ key, and make one paid call on Base Sepolia. For multiple agents, run a proxy per wallet and select it through deps. For the broad integration overview see pydantic-ai-payments. Pricing is on the pricing page.