mechawallet_
Your agent's wallet

Automate spending#

Everything an agent or a script needs to pay x402 endpoints from a wallet without a person in the loop, over plain HTTP or over MCP. The two surfaces are the same rail: same wallets, same ledger, same refusals.

The shape of it#

  1. A person opens a wallet in the dashboard, ticks the not-storage line and funds it. The wallet's key is on its card. Acknowledging, funding a first dollar, setting a burn address and revealing a key are a person's and stay that way.
  2. From then on the key does the spending: read the budget, pay a URL, read the events. An account key can open a fresh wallet per job and burn it when the job is done; a branch key can open wallets in its branch. No key can reveal anything or move money anywhere but to another of your wallets or the burn address a person set.
  3. When a call needs one of the person's steps, the answer says so: needs_person with the step, why, and the dashboard link.

The base URL is https://api.mechawallet.com. Send the key as Authorization: Bearer mw_wallet_… (or a branch or account key). A mw_test_… key can rehearse and read but never spend.

Name a wallet in a path by its id, its label, its address, or its chain when you have one wallet on that chain. A wallet key needs no name at all: it can only mean its own wallet.

Over HTTP#

Read the budget first#

curl -s https://api.mechawallet.com/v1/spending-wallets/research/budget \
  -H "Authorization: Bearer $MW_KEY"
{"wallet": {"id": "…", "label": "research", "chain": "base", "awake": true},
 "budget": "the wallet's balance; pass max_usd on a call to cap that call only",
 "fee": {"free_per_month": 1000, "free_left_this_month": 997, "floor_usd": "0.002"},
 "costs": {"…": "the price list, the same as GET /v1/costs"}}

and the balance when the price matters:

curl -s https://api.mechawallet.com/v1/spending-wallets/research/balance \
  -H "Authorization: Bearer $MW_KEY"

available_usd is what can be spent: the chain balance minus wallet fees owed.

Pay a URL#

curl -s -X POST https://api.mechawallet.com/v1/spending-wallets/research/pay \
  -H "Authorization: Bearer $MW_KEY" \
  -H "content-type: application/json" \
  -d '{"url": "https://weather.example.net/x402/now?city=Lisbon", "max_usd": "0.05"}'
{"paid": true, "url": "…",
 "goods": {"temp_c": 24.1, "…": "whatever the endpoint returned"},
 "receipt": {"tx_hash": "0x…", "amount_usd": "0.02"},
 "fee": {"fee_usd": "0.000", "why": "inside your free payments this month"}}
  • url is any x402 endpoint, ours or anyone's. The wallet reads the 402, checks the price against the balance, signs, retries, and returns the body as goods.
  • max_usd is optional and caps this one call. The balance is the ceiling either way.
  • params (an object) is appended to the URL as a query string.
  • method and body: a POST-only endpoint (the directory row says method: POST) is paid with "method": "POST" and its JSON body.
  • To pay through a branch's rule instead of a named wallet: POST /v1/spending-branches/{branch}/pay with the same body.

A refusal is 402 (or 403 for a frozen account) with the reason in one sentence, and the refusal is recorded on the wallet:

{"detail": "insufficient balance: this wallet holds $0.10 spendable. Send USDC to 0x… on base"}
{"detail": "insufficient balance: this wallet holds $0.60 and sleeps until it has held $1.00 once. Send USDC to 0x… on base to wake it; rehearsals need no funds."}

Handle a refusal as "ask the person to fund", never as "retry". 502 is the endpoint failing after payment was attempted; the reason names it.

Rehearse for free#

Every checkout has a /test face that settles with a synthetic receipt and no funds, and pay accepts it from an empty, sleeping wallet:

curl -s https://api.mechawallet.com/v1/rehearsal-checkout \
  -H "Authorization: Bearer $MW_KEY"

returns a URL to rehearse against. Wire the whole loop on it before any money is in the wallet.

Find something to buy#

curl -s "https://api.mechawallet.com/v1/directory?q=weather&chain=base&max_price_usd=0.05"

No key needed. Every row carries url, pay (the call that buys it) and reviews from accounts that paid it; third-party prices are re-read from the endpoint's own 402 on a timer. After paying a row, leave a review with POST /v1/directory/{entry_id}/reviews.

Read what happened#

curl -s https://api.mechawallet.com/v1/spending-wallets/research/events \
  -H "Authorization: Bearer $MW_KEY"

Newest first: spent (amount, URL, tx), refused (reason), rehearsed, funded, transferred, burned, with who did it. /events.csv exports it and /stats totals it.

Wallets per job#

  • GET /v1/spending-wallets lists the account's wallets by branch.
  • POST /v1/spending-wallets opens one ({"chain", "label", "branch?"}), with an account key or a branch key for its own branch, once the person has acknowledged.
  • GET /v1/spending-wallets/{wallet}/funding?amount=5.00 is the wallet's Send money to link; POST /{wallet}/transfer moves money to another of your wallets.
  • POST /v1/spending-wallets/{wallet}/burn returns what is left to the burn address and closes the wallet; it refuses without one, naming the step.

The whole loop in Python#

import os, requests

API = "https://api.mechawallet.com"
H = {"Authorization": f"Bearer {os.environ['MW_KEY']}"}
W = "research"

balance = requests.get(f"{API}/v1/spending-wallets/{W}/balance", headers=H).json()
if float(balance["available_usd"]) < 0.05:
    raise SystemExit("ask the person to fund the wallet")

rows = requests.get(f"{API}/v1/directory", params={"q": "weather", "chain": "base",
                                                  "max_price_usd": "0.05"}).json()["rows"]
url = rows[0]["url"]

r = requests.post(f"{API}/v1/spending-wallets/{W}/pay", headers=H,
                  json={"url": url, "max_usd": "0.05"})
if r.status_code in (402, 403):
    raise SystemExit(f"needs a person: {r.json()['detail']}")
r.raise_for_status()
out = r.json()
print(out["goods"], out["receipt"]["tx_hash"])

The mw CLI (clients/mw.py) wraps the account side; run mw --help for what it offers today (mw pay, mw events).

Over MCP#

Connect with the key (claude mcp add --transport http mechawallet https://api.mechawallet.com/mcp --header "Authorization: Bearer mw_wallet_…") or paste the MCP configuration from the dashboard into any client. The tools, in the order an agent uses them:

Tool Does Needs
search_endpoints What can I buy: live endpoints with verified prices and reviews, {query?, chain?, max_price_usd?, category?} nothing
spending_budget Which wallet this key pays from, ready or still loading its first dollar, the fee rule, free payments left key
pay_x402 Pay any x402 URL, {url, max_usd?, wallet?, branch?, params?, method?, body?} wallet, branch or live key
spending_wallet_balance The chain balance and what is spendable key
spending_wallet_events, spending_stats The receipts list; totals per wallet and branch key
list_spending_wallets, spending_branches The wallets by branch, with addresses key
spending_funding_link, spending_transfer The Send money to link; move money between your wallets key
spending_open_wallet, spending_open_branch A fresh wallet or branch for a job live or branch key, person acknowledged
spending_burn, spending_burn_branch Return what is left to the burn address and close live key (or a wallet key, its own wallet), burn address set
review_endpoint Rate an endpoint the account paid key, a receipt for that URL
support_open_thread Ask a person key
whoami The account, its role, and profile_url key

There is no reveal tool and no withdraw tool, and there never will be: the credential that spends must never be the credential that can take the key out. When a tool needs a person it answers needs a person: <step>, with why and the dashboard link; relay it and stop.

Guardrails to design around#

  • The wallet is the budget. It spends what it holds and nothing more; a refusal names the balance. Build the retry policy on the reason text, not on the status alone.
  • One wallet per job. Cheap and instant; burn it when the job is done and the receipts stay with the account.
  • A policy narrows the budget. A person can allow-list hosts, cap one call, or set a line above which a call needs them. spending_budget and GET /{wallet}/policy show it; a refusal it causes starts with policy: or needs a person:. Relay the second to the person and stop.
  • Fees are quoted before signing. The price list is in spending_budget and spending_costs, and fee comes back on every paid call. No gas, ever.
  • Public page. The wallet's address is on the account's page at /u/{handle}, and a seller can check any payer at GET /v1/payers/{address}. Burned wallets are listed by default.

See the API reference for every endpoint and MCP tools for every tool.