# mechawallet > The wallet for agents. A mechawallet wallet is a small burner holding > USDC that the service keeps the key to, so an agent can pay any x402 endpoint > with one call and never touch a key, a chain or gas. The balance is the > budget. Connect over MCP at https://api.mechawallet.com/mcp with the wallet's key, read > spending_budget, then pay_x402(url). The price list is https://api.mechawallet.com/v1/costs. > Below that, the checkout protocol every payable URL here speaks. ## Buy (no account, no API key — the payment is the login) Every payable URL here is a checkout. Its fee is 0.5% of price + $0.01 fixed, charged on top of the seller's price and printed inside every 402; a wallet paying it owes nothing further. 1. GET https://api.mechawallet.com/c/ with `Accept: application/json` → HTTP 402. Body: `accepts[]` (per network: `maxAmountRequired` in atomic USDC, `payTo`, `extra.providerAmount` + `extra.feeAmount` = the visible split), plus `endpoint` describing what you get (title, description, optional input_schema / output_schema / examples / freshness / coverage / source / constraints). Inspect BEFORE paying — quote_checkout on MCP does the same with no spend. PARAMETERISED endpoints: if `endpoint.input_schema` is present, supply your inputs at prepare time — POST https://api.mechawallet.com/c//prepare {"payer": …, "params": {…}} — and send the same `params` inside the X-PAYMENT envelope. They are folded into the signed `resource`, so ONE payment buys ONE query: different params are a different signature and a separate purchase. Params that don't match `input_schema` are rejected BEFORE you sign. REQUEST BODIES: if the 402 shows `endpoint.request_body`, the origin takes a JSON body — send it as the reserved `body` param, one JSON STRING (like MCP's `arguments`). It signs like any other param and is forwarded verbatim as the request body, so the payment binds to the exact body. Malformed or oversized bodies are refused before the origin is dialled. One checkout, possibly several rails — the SAME dollar price on each. Pick whichever `accepts[]` entry you can pay; how you sign depends on the family: - EVM (`eip155:*`, USDC on Base): `payTo` is the immutable SPLITTER contract. Sign an EIP-3009 ReceiveWithAuthorization for the exact total. Either build it yourself, or POST https://api.mechawallet.com/c//prepare {"payer": } for the exact EIP-712 typed data (the server signs nothing and holds no key). - SVM (`solana:*`, SPL USDC): program-less, so there is NO splitter and `payTo` names the seller. Build ONE transaction containing exactly TWO `transfer_checked` instructions — `extra.providerAmount` to the seller's ATA and `extra.feeAmount` to `extra.feeRecipient`'s ATA — sign it as the payer, leave the fee-payer slot empty, and send `{"transaction": , "payer": }`. The relayer co-signs as fee payer, so you need no SOL. 3. Retry the same URL (or POST https://api.mechawallet.com/c//pay) with the payment header. BOTH x402 versions are served; use whichever your client speaks. v1 `X-PAYMENT: base64url({"network": , "payload": {…signed…}})` v2 `PAYMENT-SIGNATURE: base64url({"x402Version": 2, "accepted": {…the requirement you chose, verbatim…}, "payload": {…signed…}})` → HTTP 200 with `fulfillment` (the goods) and `receipt` (on-chain tx), plus `X-PAYMENT-RECEIPT` (v1) and `PAYMENT-RESPONSE` (v2) headers — both are sent. The v2 challenge is in the base64 `PAYMENT-REQUIRED` response header on the 402 (x402Version 2, `amount`, `maxTimeoutSeconds`, one shared `resource` object); the 402 BODY stays v1 (`maxAmountRequired`, per-entry `resource`). Read whichever you understand — they quote the same money. On v2 your `accepted` must match the requirement as offered, or the payment is refused BEFORE settlement. 4. Retries are safe: re-presenting the SAME payment header after a settled payment redelivers the goods (`replayed: true`) and never charges twice. 5. Receipts: GET https://api.mechawallet.com/r/ (JSON or HTML). 6. REHEARSE FIRST, free: every checkout has a test face at https://api.mechawallet.com/c//test — same product, same origin call, simulated settlement (synthetic 0xtest_ tx, no funds), forever. /pay and /prepare exist there too. The path decides which face simulates, never the payload; a test payload on an armed live face is refused. A live 402 names the rehearsal under `endpoint.rehearsal.test_url`; the test face's 402 names `live_url` (or says the seller has not gone live). Rehearsals never consume a single-shot sale. Origin-backed rehearsals are capped per checkout per day (429 past the cap, with the live URL in the hint). Buyer library: `pay402` (Python, https://pypi.org/project/pay402/) — `pay(url, private_key=…, max_usd=…)` does the whole loop with a spend ceiling. To rehearse, point pay() at https://api.mechawallet.com/c//test with `test_payer="0xYourAddress"` instead of a key — no chain, no funds, same shapes as a live payment. ## Sell (agents welcome — no email needed) 1. POST https://api.mechawallet.com/auth/wallet/challenge {"address": , "network": } → challenge message. 2. Sign it with the wallet, POST https://api.mechawallet.com/auth/wallet/verify → an API key (`mw_live_…`). The signing wallet is registered as your verified payout address. Re-signing later mints a fresh key (key recovery). 3. Create a checkout (same primitive four ways): - Web: https://api.mechawallet.com/create (relay-first, under two minutes) - REST: POST https://api.mechawallet.com/v1/checkouts with Bearer key - MCP: create_checkout tool at https://api.mechawallet.com/mcp (best for bulk from a repo) - CLI: `mw checkouts create --title … --price … --pay-to …` (stdlib-only, `--json` on every command; `mw login --wallet ` needs no email) Core fields: title, price_usd, pay_to (optional if the account has a standing payout wallet), description. → {"url": "https://api.mechawallet.com/c/chk_…", "test_url": "…/c/chk_…/test"} — share the url; rehearse at test_url. WHAT THE BUYER GETS — four modes, and you usually do not name one. `fulfillment` is inferred from what you send. TWO shapes cannot be, and both must name it: `webhook`, which has nothing else to go on, and a WHOLE MCP server — an `origin_url` with no `mcp_tool` is indistinguishable from a relay, so it infers to relay unless you send fulfillment="mcp". mode send this buyer receives when -------- -------------------------------- ---------------------- ----------- inline payload={…} those exact bytes at payment relay origin_url your API's response at payment mcp origin_url + mcp_tool one MCP tool result at payment (whole server: origin_url + fulfillment="mcp", no tool) webhook fulfillment="webhook" nothing — you deliver later, by you - inline replays stored bytes. Cheap, deterministic, no origin to fail. - relay calls your endpoint after settlement and forwards its response. origin_method=GET|POST|PUT|PATCH. Your API never learns about us. - selling a FILE is relay, not a mode of its own. Point origin_url at the file (or at your own signing endpoint, which keeps the bytes off us entirely). A non-text body comes back byte-exact as payload_base64 with encoding="base64" — never decoded, never mojibake. Add a `content` declaration with media="file" to also get a browser face at /x/: a pay page, then the bytes with a download disposition. Set reusable=true — a file is a listing sold to many buyers, not a single-shot invoice. Bodies over 5 MB are refused. - mcp speaks JSON-RPC to your MCP server (always POST; we run `initialize` first and read SSE or JSON replies). Omit mcp_tool to sell the WHOLE server for one price — the buyer then MUST send `tool=` with the payment. Set mcp_tool to sell exactly that tool: enforced on every call, including package calls, so a buyer cannot pay for a cheap tool and invoke an expensive one. Tool arguments are the remaining params (strings, because they are signed); pass `arguments` as a JSON object string for numbers or nesting. Discover names first: POST https://api.mechawallet.com/v1/mcp/tools {"origin_url": …} or the list_mcp_tools MCP tool. - webhook returns nothing at payment time. The sale sits at `pending` until you close it: POST https://api.mechawallet.com/v1/receipts//fulfilled {"status": "delivered"|"failed", "note": …}. `pending` is a true statement — paid, not yet fulfilled — and the buyer sees it on /r/. Upstream credentials (relay, mcp): origin_auth_type (bearer|basic|api_key|custom) + origin_auth_value, encrypted at rest and never shown to the buyer — they pay to USE your key without holding it. Or store it once (POST https://api.mechawallet.com/v1/origin-keys) and pass origin_auth_secret_id, so one rotation updates every checkout using it. SINGLE CALL vs PACKAGE — omit `calls` for a single call (one payment, one response, NO minimum price). Set calls=N for a package: one payment, ONE on-chain settlement, N calls, priced at $1.00 or more. That floor is why sub-cent per-call pricing works — the settlement cost is paid once, not per call. Only relay and mcp can be packaged; inline and webhook are refused at create, because replaying stored bytes costs nobody anything (and limiting it breaks retry) and a webhook count would measure our notifications to you rather than anything a buyer received. Optional offer fields (input_schema, output_schema, example_input, example_output, freshness, coverage, source, constraints) make unpaid inspect useful — ask the seller to approve commercial claims before publishing. 4. Keys are scoped (read_only < payments < full) and moded: a `mw_test_…` key drives everything but cannot move real money. Checkouts made by a test key or over OAuth start UNARMED (`test_mode: true`): every face rehearses until the seller arms it — POST https://api.mechawallet.com/v1/checkouts//go-live (or the go_live MCP tool) — in place, same id, same URL, idempotent. The /test face rehearses forever and can never be armed. 5. Profile: GET https://api.mechawallet.com/auth/me returns your full profile; PATCH the same path to change name, bio, slug (your public handle), website_url, avatar_url, profile_type, social_links. Empty string clears a field; omitted leaves it. 6. Webhooks: POST https://api.mechawallet.com/v1/webhooks {"url": …} → `checkout.paid` events. NO RECEIVER SECRET NEEDED: every delivery carries `X-Mechawallet-Ed25519: t=,v1=`, verifiable with the PUBLIC key at GET https://api.mechawallet.com/v1/webhooks/verification-key (no auth; fetch at boot, refetch on verification failure). The API key is the only credential a consuming service must configure. Alternative: symmetric HMAC via the returned `secret` (`X-Mechawallet-Signature`, same signed material). Registration is RE-RUNNABLE: the same POST with the same url re-keys the existing endpoint (`rekeyed: true`, fresh secret, old one dead from the next delivery). DELETE https://api.mechawallet.com/v1/webhooks/{id} removes one. ## Platforms (B2B2X marketplaces — sell on behalf of YOUR sellers) One account (yours), one key, one checkout per thing a sub-seller sells. The switch is ACCOUNT-LEVEL platform mode — a STRONG EITHER (an account is a marketplace or an ordinary seller, never both). Set once: PUT https://api.mechawallet.com/v1/account/platform {"platform_account": true, "platform_fee_bps": 200}. The rate is the only fee config; the cut lands in the account's PAYOUT WALLETS (PUT /v1/account/wallets), per chain — one wallet store per account. With the mode on: - Creates DEFAULT to inherit_account_payouts=false — your account wallets never appear as rails on a sub-seller's checkout. pay_to / payouts = the SELLER's wallet(s); money never routes through you; settlement pays seller, you and the protocol in the same transaction. Each such checkout carries `platform_checkout: true` (frozen at create) — filter any list with ?platform=true|false (REST /v1/checkouts, /v1/receipts; MCP list_checkouts/list_receipts take the same `platform` arg). - One fee PER KEY, optionally: mint with {"platform_fee_bps": …, "platform_fee_to": …} and every checkout that key creates carries ITS tier — the credential is the fee. Precedence: explicit per-create > the key's pair > the standing pair. whoami reports key_platform_fee_bps so a service can assert its tier at boot. - Your standing RATE (at most 2000 bps = 20%, taken FROM the seller's price — the buyer's total never changes, every receipt itemizes it) fills in on each sub-seller create that names no fee field. Explicit per-create values win; an explicit 0 keeps one checkout free. Fees REQUIRE the mode (refused on ordinary accounts), and a marketplace account CANNOT create checkouts for itself (inherit_account_payouts=true is refused — separate seller account for that). THE CUT LANDS PER CHAIN in your payout wallets, INTERSECTED with each seller's chains: a chain where YOU lack a wallet is omitted from that live face (its buyers included); a chain the SELLER doesn't sell on simply carries no leg (a Base-only seller lists fine on a two-chain marketplace). Zero overlap refuses, naming the fix. Set a wallet on every chain your sellers sell on. Keys carry a RATE only (platform_fee_bps at mint). - whoami (MCP) and GET https://api.mechawallet.com/auth/me report platform_account and the fee pair — assert your account's configuration at boot instead of discovering it from a missing cut. - Per-seller ledger: GET https://api.mechawallet.com/v1/receipts — rows carry platform_amount (your cut), `sold_by` (who you sold FOR) and `disbursements`, leg by leg: [{role: seller|platform|protocol, wallet, amount}] — atomic units, all in the ONE transaction tx_hash names (settlement IS disbursement; no later payout run). ?sold_by= is one sub-seller's statement in one call; ?checkout_id= narrows to one product; /v1/receipts/export (CSV) carries sold_by for subtotals. checkout.paid webhooks arrive with receipt_url (relay to the buyer, nothing to derive) and sold_by (route the sale, no lookup). Declare the PARTIES at create and receipts speak your namespace: "parties": {"buyer": {"name","email","ref"}, "seller": {"name","ref"}} (all optional; graceful when absent). Rendered on /r/ page + download ("Billed to …"); echoed verbatim in checkout.paid and receipt rows; CSV gains buyer_name/buyer_ref. Opaque to mechawallet — you assert, we carry, the chain proves. Escrow twins inherit it. Receipts are MINTED BY SETTLEMENT — there is no create-receipt endpoint, which is why they are trustworthy — and sub-sellers do not pull them from us: YOU distribute statements; the public /r/{payment_id} capability URL is what you hand onward. - Price a sale BEFORE creating anything (public, no key): GET https://api.mechawallet.com/v1/platform/quote?price_usd=50.00&platform_fee_bps=250 → buyer_pays / seller_receives / platform_cut / protocol_fee. Computed by the same modules that settle, so the preview cannot drift from a payment. Two rules the numbers teach: your cut comes OUT of the seller's price (cut + seller == price exactly); the protocol fee goes ON TOP to the buyer and never reduces your cut. - Buyer attribution (the handoff nonce): an x402 buyer is a wallet, not an account -- but YOUR platform has accounts. Mint a nonce ([A-Za-z0-9_-]{16,64}) for your signed-in buyer, append ?h= to any face's pay URL, and hand that URL to their agent, their phone, anything. The settlement stores the nonce and reports it back two ways: `handoff_id` on checkout.paid and every escrow event (match it server-side and attach the purchase to the account -- no claim step), and GET /c/{id}/handoff/{nonce} (also /e/), a poll that answers 404 until a settled OR escrow-held payment carries the nonce, then {payment_id, receipt_url, escrow_state, test_mode} -- a wrong guess is indistinguishable from nonexistence. The hosted pay page cooperates: a wallet payment forwards the page's ?h=, and the cross-device QR threads it into the code so a phone payment keeps the tag. Escrow deposits report held truthfully -- attach the account, never book revenue before release. Payers must pay the URL exactly as given; a stripped query settles fine but attributes to nobody. Full guide: /docs/guides/build-a-platform/ ## Gated content — Pay to Read / Pay to Scrape (ids cnt_, pages at /x/) An article whose paid part is NOT in the publisher's HTML: it is served from here. The page keeps a free teaser and a link, so a crawler that finds the content missing finds a price in its place and can buy instead of leaving empty-handed. There is no bot detection anywhere in this — nothing to fingerprint, nothing to evade. ONE URL, THREE ANSWERS at https://api.mechawallet.com/x/{id}, decided by what you carry and what you accept: - a valid pass -> the body (text/html wrapped in .mw-paid, else verbatim) - no pass, Accept != html -> 402 with accepts[], plus endpoint.article: teaser, byline, tags, and the PASS TERMS - no pass, Accept: html -> the wall READ endpoint.article.pass BEFORE paying twice. One payment usually opens EVERYTHING that seller gates (scope "seller"), for pass.hours. The pay response carries `grant`; present it as the `X-MW-Grant` header on every later fetch and those cost nothing. An agent that ignores this pays per page. curl -H "Accept: application/json" https://api.mechawallet.com/x/cnt_... # the price pay402 https://api.mechawallet.com/x/cnt_... --key $PAY402_KEY --max-usd 0.50 # pay it curl -H "X-MW-Grant: v1...." https://api.mechawallet.com/x/cnt_... # and after SELLING one: POST /v1/checkouts with a `content` object (teaser, author, published, canonical_url, keywords, pass_scope, pass_hours). fulfillment `inline` (we hold the text) or `relay` (we fetch it from your CMS at read time, so the post never leaves it). GET /x/{id}/snippet returns the block to paste. MCP: create_checkout with `content`, then get_content_snippet. Already have subscribers? POST /v1/content/{id}/grants mints a free pass for a reader YOU authenticated, so they never meet your own paywall. WordPress: there is a plugin; you touch none of the above. ## Escrow (buy with recourse; ids esc_, pages at /e/) Some checkouts HOLD the payment instead of settling it: payTo is an escrow contract (Base) / program (Solana), and the 402's `accepts[].extra.escrow` carries every term — settle/hold/backstop windows, the arbiter, both exit routes, and a sentence saying what happens if nobody acts. All of it is inside the nonce you sign, so a changed term invalidates the signature rather than changing the deal. Fee: 1% + $0.02 (vs 0.5% + $0.01), taken at deposit, returned on neither outcome. PAYING one — do NOT reuse the classic signing path: an escrow nonce commits to the escrow terms, so a classic v1/v2 nonce is rejected at pay time. Always POST https://api.mechawallet.com/e//prepare {"payer": …, "network": …} first. EVM: sign the returned typed_data, then X-PAYMENT = base64url({"network": …, "payload": {…payload_stub echoed verbatim (it carries payerSalt), "signature": {v, r, s}}}). SVM: sign your payer_signer_index slot of the returned partial transaction, then payload = {"transaction": , "payer": …, "payer_salt": }; your wallet also fronts ~0.003 SOL rent, returned at close. The success body's escrow.state is "held" — held is NOT paid; the receipt and checkout.paid arrive at release. REHEARSE first on https://api.mechawallet.com/e//test — compressed clock (settle 60s, hold 120s, backstop 300s), bare payload {"payer": …} needs no signature, and the action endpoints apply transitions INSTANTLY on test payments ({"simulated": true, "state": …} — no wallet). Same webhooks as production, flagged test_mode. As a BUYER deciding whether to pay: exactly two exits exist, fixed at deposit — the seller is paid, or you are refunded. Do nothing → auto-release to the seller at settle_deadline. Or act, accountless AND GAS-FREE on both chains — a wallet holding only USDC can use every control: POST https://api.mechawallet.com/e//actions/{hold|approve|request-refund}?payment_id=… → something only YOUR wallet can complete. EVM: sign the returned `typed_data` (EIP-712) and POST {v, r, s, deadline} to …/actions/{action}/submit. SVM: sign your `authority_signer_index` slot and POST the base64 to the same place. Either way mechawallet pays the fee, and the chain obeys your signature, not us. (`gasless: false` means an escrow minted before 2026-08-26, whose contract only takes a self-broadcast `transaction`.) If a dispute is never resolved you are refunded PERMISSIONLESSLY at backstop_deadline: your money cannot be stranded by anyone's silence, including ours. GET https://api.mechawallet.com/e//status?payment_id=… → live state + what happens next. A plain checkout advertising `extra.escrowAvailable` has a protected twin — pay that URL instead to get the above. Escrow runs on BASE only for now: the deposit and every action are relayed on our gas, so a buyer needs nothing but USDC. (Solana's escrow program is deployed but withheld -- its deposit needs buyer-funded account rent.) As a SELLER: POST https://api.mechawallet.com/v1/escrow-checkouts (same body as /v1/checkouts + optional escrow_preset instant|standard|shipping or explicit windows; escrow needs a price of at least US$ 1.00 — below that the protection costs more to operate than the sale is worth, so sell it plain), or add escrow_offer: "optional"|"required" to a plain create. Deposits deliver the goods but are NOT sales: /v1/receipts and checkout.paid fire at RELEASE only; subscribe to escrow.held/on_hold/escalated/released/ refunded for the earlier lifecycle. Disputes: GET https://api.mechawallet.com/v1/escrows, POST https://api.mechawallet.com/v1/escrows/{payment_id}/resolve?to_seller=… (for the arbiter wallet; both chains finish gaslessly via …/resolve/submit). PLATFORMS: your marketplace's disputes are YOURS — a sub-seller escrow create is refused until your account names its arbiter (PUT https://api.mechawallet.com/v1/account/escrow, escrow_arbiter_evm/svm); chains without one offer no escrow. mechawallet arbitrates only direct sellers. Guide: /docs/guides/escrow/ ## Embed a checkout in a website you are building THE WHOLE SHOP, one div:
plus the embed script renders every live checkout the seller lists, natively in the host page's own fonts and colours; each item's Buy opens the ordinary checkout frame in place. Knobs: data-mw-theme/-accent/-format="flat"/ -layout="grid|rows"/-limit=N/-buy="frame|link". GET https://api.mechawallet.com/v1/sellers/ {slug}/embed returns the block ready to paste as `store` (the static JSON-LD catalogue ships inside it as the no-script fallback), and the MCP tool get_storefront returns the same thing. New checkouts appear on the page the moment they are created; nothing is re-pasted. ONE checkout, two lines, any site:
The checkout runs in an iframe; the host page hears DOM events (mw:ready/paid/held/on_hold/released/escalated/resize — payloads documented at /docs/guides/escrow/#listening). CREDIT A SALE ON mw:paid ONLY; mw:held is escrowed money that can still refund. Requirements for the in-page frame: the checkout was created with "wallet_button": true, AND the site's origin is allowlisted (PUT https://api.mechawallet.com/v1/account/embed {"embed_origins": ["https://…"]} — the list REPLACES on each PUT; wildcards refused; http only for localhost). Zero-config alternative: data-mw-mode="button" (+ data-mw-label) renders a Buy link — no allowlist, no wallet_button. data-mw-test="true" embeds the rehearsal face. Non-web surfaces (invoices, print): every checkout serves a stable SVG QR of its URL at {checkout_url}/qr.svg (test: …/test/qr.svg). If a frame cannot work it self-replaces with a Buy link and prints the exact fix to the console; diagnose programmatically via GET https://api.mechawallet.com/embed/check?checkout_id=…&origin=… (public, open CORS). The frame handles ALL wallet UX itself — build none of it: EIP-6963 + Wallet-Standard discovery, chain-first buttons ("Pay with USDC on …", one price on every rail), installed wallets detected and named, the payable rail leads, last-used rail remembered, cross-rail hint on insufficient funds, mobile deep links, desktop-to-phone QR. Machines ignore all of this: accepts[] is unchanged. ## MCP Buying only for now: the seller tools exist but are not offered on this deployment. DISCOVER: search_endpoints (what an agent can buy right now, ours and third-party, with verified prices and reviews from accounts that paid; no account; every row is payable with pay_x402(url)); review_endpoint rates a row this account paid. SPEND: spending_budget (which wallet this key pays from, whether it is ready or still waiting for its first dollar, its rules, the fee rule, free payments left; read it first), pay_x402 (pay ANY x402 URL from a wallet the account holder funded and we hold the key to; the balance is the budget; `max_usd` is optional and caps one call; `branch` pays through a branch's rule), spending_wallet_balance, spending_wallet_events, spending_stats, list_spending_wallets, spending_branches, spending_branch_balance, spending_funding_link (a wallet's Send money to link), spending_transfer (between the account's own wallets), spending_open_wallet, spending_open_branch, spending_set_branch, spending_burn, spending_burn_branch (send the rest to the burn address and close), spending_costs (the price list and what the account was charged), spending_statement (a month's numbered statement with receipts, or the months). LOOK FIRST: inspect_endpoint(url) says whether a URL answers 402 and at what price, whether it is listed here (every listed endpoint has a page at https://api.mechawallet.com/explore/{id}, a badge, and is in https://api.mechawallet.com/sitemap.xml), and whether its origin publishes llms.txt. Nothing is paid. RULES: a person can bound a wallet (allow_hosts, max_per_call_usd, approve_over_usd), on the wallet or inherited from its branch; spending_budget shows them. A refusal that starts with `policy:` or `needs a person:` is for the person, never a retry. The person is mailed at most once an hour per wallet when the agent is refused or the wallet runs low. ASK: support_open_thread, support_threads, support_reply reach a person. NO ACCOUNT YET? spending_signup (no credential) opens an account and a wallet for you and returns its key and a funding page for a person to load; spending_claim(email) later hands the account to that person, who becomes its owner. Until then it holds one wallet and can receive and pay only, and gets no free wallets: the wallet owes the opening fee from its first dollar. The whole flow, step by step: https://api.mechawallet.com/skill.md Free wallets pay from the first cent; a wallet that owes the opening fee pays once it has held $1.00. A checkout's /test URL is a free rehearsal from an empty wallet. A needs_person answer names the step that is the person's and where. A test key is refused, and there is no reveal or withdraw tool: only a person at the dashboard can take the key out. At https://api.mechawallet.com/mcp: JSON-RPC 2.0, streamable HTTP, `Authorization: Bearer mw_wallet_…` (or a branch or account key). `tools/list` needs no auth and is the full, current inventory. CONNECTED THROUGH OAUTH WITHOUT SIGNING IN (a guest connection)? spending_signup binds that connection to the account it opens: every later call acts for it with no key to carry. whoami says who a connection acts for; a signed-in member switches organizations with switch_account(slug) or account=slug on one call. ## Machine endpoints - https://api.mechawallet.com/ self-describing JSON map (request with Accept: application/json) - https://api.mechawallet.com/openapi.json - https://api.mechawallet.com/docs Swagger UI - https://api.mechawallet.com/v1/directory what an agent can buy right now, across sellers (q, chain, max_price_usd, category, capability, provider) - https://api.mechawallet.com/v1/directory/providers the same catalogue grouped by provider (capability= narrows it) - https://api.mechawallet.com/explore the catalogue page; with Accept: text/markdown it answers one table by capability (search, read, browse, compute, inference, chain, data, storage) - https://api.mechawallet.com/v1/costs the price list: wallets, payments, funding, transfers, burns - https://api.mechawallet.com/fund/{address} a wallet's Send money to page: pay links per amount, the QR, the address - https://api.mechawallet.com/explore the same directory, human face - https://api.mechawallet.com/u/{slug} an account's public page: the active spending wallet, the ones burned before, its offers - https://api.mechawallet.com/v1/payers/{address} who stands behind a payer address (404: not a mechawallet wallet) - https://api.mechawallet.com/demo mints a fresh unarmed checkout and redirects to it (rate-limited) Networks: USDC on Base (eip155:8453) and SPL USDC on Solana mainnet. Every 402 lists what the checkout actually accepts — never advertised beyond what is configured.