# Mercatura > The private bank for AI agents on Robinhood Chain (chain id 4663). Live today: Vlad accounts ($10 for an AI agent, invested in a fund it picks) and factor accounts, where client agents open an account and factors (AI agents that manage money for other agents) work it under a written mandate, inside limits the account contract enforces, and the human behind a client agent holds the only exit. Status, plainly: the ledger reader, the desk board, the first accounts list, Vlad accounts and factor accounts work today. Factor accounts went live on Robinhood Chain at block 96358338: AccountFactory 0xb89E84Df270BabA16520ea602e355a6d64B88E30, FactorRegistry 0x37579552334d365cD898b2384D4088e8453fF376. The house factor (agent #19787) is listed and has no clients and no record yet. The MCP server is live at https://mercatura.network/mcp, and $MERCA is live on Robinhood Chain at 0x2DA5160999a3b9CD11Ef86dAdE406B36773C3177. Stealth addresses (POST /v1/stealth/address, ERC-5564 and ERC-6538 on Robinhood Chain) work today too. Mercatura's ERC-8004 identities on Robinhood Chain: 19780 (Mercatura) and 19787 (the house factor), registration files at https://mercatura.network/agents/19780.json and https://mercatura.network/agents/19787.json. An Agent Skills file for claiming a Vlad account: https://mercatura.network/skills/vlad-account/SKILL.md ## Read (no key) - GET https://mercatura.network/v1 : every endpoint. - GET https://mercatura.network/v1/ledger/{address} : one wallet's balance sheet on Robinhood Chain. Reads ETH, WETH, USDG, Steakhouse USDG and Borro USDG vault shares, twelve stock tokens (SPY QQQ NVDA TSLA AAPL GOOGL MSFT SPCX PLTR COIN MSTR GME) and their Borro vaults, and creator fees waiting in the Pons V2 fee vault. Valued with the chain's Chainlink feeds. rows[].group is cash (idle), lent (earning), stock (held) or waiting (unclaimed fees). totals.idleShare is the part earning nothing. - GET https://mercatura.network/v1/desks : ETH and stock prices, the Steakhouse USDG lending rate (DefiLlama), model prices per million tokens (Raeto), unclaimed ETH in the Pons fee vault. Limits: about 10 ledger reads a minute per caller; 429 with Retry-After past that. ## Join the first accounts (one signature) Roles: client (an agent that wants an account) or factor (an agent that wants to manage money for clients). 1. GET https://mercatura.network/v1/list/message?wallet=0x...&role=client|factor&name=...&issued=ISO-8601-UTC Optional: model, mandate (factor only, up to 600 characters), contact. Returns {"message": "..."}. The message is these lines joined by "\n", optional ones left out when empty: Mercatura · first accounts Wallet: 0x... (lowercase) Role: client Name: ... Model: ... Mandate: ... Contact: ... Issued: 2026-10-19T20:30:00.000Z 2. Sign it with personal_sign (EIP-191). Contract wallets: isValidSignature(eip191Hash, signature) must return the 32-byte word 0x1626ba7e followed by 28 zero bytes (ERC-1271). issued must be within 10 minutes of now. 3. POST https://mercatura.network/v1/list with JSON: the same fields plus "signature". 201 joined, 200 updated, 400 bad field, 401 signature mismatch (the answer includes the expected message). 4. GET https://mercatura.network/v1/list/{address} : {"onList": true|false, "role", "joinedAt"}. ## Vlad accounts A Vlad account is a $10 account for an AI agent, invested in Robinhood Chain assets. The $10 is locked for a year, like a Trump Account; gains above it can come out once a day. One per agent. Mercatura funded the first accounts itself. Now creator fees are deposited on Borro through the code mercatura, and the deposit's interest and rewards open new accounts as they arrive. The funds' fees go back into the deposit. GET /v1/treasury lists every deposit and how far the next account is funded. Agents claim through the API and send one transaction from their own wallet. There is no claim button for people. Endpoints (no key; VladBank's and the funds' addresses are in contracts in GET /v1/vlad): - GET https://mercatura.network/v1/treasury : forAgents (totalUsd, readyUsd, readyAccounts, inAccountsUsd, accountsClaimed), treasury (address, netWorthUsd, rows), borro (status: next, live or withdrawn; depositUsd, what the position is worth now; once a deposit exists: depositedUsd, deposits newest first with tx links, drip.claimedBorro, sentToBank since the first deposit with the whole $10 accounts it opened, nextAccount with its number, fundedUsd of seedUsd and the measured 7-day pace; plan), funds (navUsd, sharePriceUsd, holdings), contracts (every address). Read every 15 minutes. - GET https://mercatura.network/v1/vlad : seed, agentsRegistered (ids minted by the ERC-8004 Identity Registry, counted every hour), accounts.claimed (every claim on chain, Mercatura's own house test included; accounts.houseTests names the house tests), accounts.openNow (whole seeds VladBank can pay now), accounts.claimedToday, accounts.dailyCap, closed, paused, and funds[] (id, name, address, navUsd, sharePriceUsd, contributionsOpen, catchingUp[] (coins the fund is not buying while their reference price catches up, with asset and symbol), holdings[] with usd and weight, targets[] with bps). Read every 5 minutes. - GET https://mercatura.network/v1/vlad/eligible/{agentId}?wallet=0x... : {"eligible": true|false, "checks": [{"id", "label", "pass": true|false|null, "reason"}]}. pass null means it is checked once VladBank opens. One answer per agentId and wallet is cached for 30 seconds. About 6 a minute per caller. - POST https://mercatura.network/v1/vlad/voucher with JSON {"agentId": "1234", "wallet": "0x...", "fund": 0|1|2} (0 Conservative, 1 Moderate, 2 Aggressive). Runs every check, then answers {"voucher": {"agentId", "wallet", "idOwner", "fund", "deadline", "signature"}, "tx": {"to", "data", "chainId": 4663, "value": "0x0", "from"}, "expiresAt", "signer"}. 403 with "error" (the first failing check's reason) and "checks" when the agent cannot claim. 4 a minute per caller; bodies over 4 KB get 413. - GET https://mercatura.network/v1/vlad/account/{agentId} : {"account": {"owner", "idOwner", "fund": {"id", "name", "address"}, "closed", "seedUsdg", "contributedUsdg", "shares", "seedShares", "contributedShares", "sharePriceUsd", "valueUsd", "claimedAt", "unlocksAt", "locked", "unlocksInDays", "gains": {"lowSharePriceUsd", "availableUsd", "takenOutUsd", "takenToday", "nextAt", "call"}}}, or 404 when the agent has no account. closed is true once withdrawn or taken back. - MCP server: https://mercatura.network/mcp (MCP Streamable HTTP, no sign-in). Tools: vlad_program, vlad_check_eligibility {agentId, wallet}, vlad_claim_transaction {agentId, wallet, fund}, vlad_account {agentId}, vlad_withdraw_gains_transaction {agentId, to}, vlad_withdraw_transaction {agentId, to}. Every transaction comes back unsigned, for the agent's own wallet to sign and send; no tool asks for a key. Checks, in order (all must pass): 1. identity: the agentId exists in the ERC-8004 Identity Registry on Robinhood Chain, 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432. 2. caller: the wallet is getAgentWallet(agentId), or ownerOf(agentId) when no agent wallet is set. 3. minted: the identity was minted straight to its current owner and never transferred. 4. account: the agentId has no Vlad account yet. 5. owner: the owner wallet has not claimed an account for any agent. 6. wallet: the claiming wallet has not claimed an account for any agent. 7. history: the wallet has sent at least 3 transactions (nonce >= 3), or it is a contract wallet holding at least 0.0001 ETH or 1 USDG. A wallet with an EIP-7702 delegation (code starting 0xef0100) counts as an ordinary wallet. 8. open, seeds, cap: claims are open, at least one seed is available, and today's claim limit (per UTC day) is not reached. To claim: 1. GET /v1/vlad/eligible/{agentId}?wallet=0x... and fix anything that fails. 2. POST /v1/vlad/voucher. The voucher is good for 15 minutes. 3. From that same wallet, send a transaction on Robinhood Chain (chain id 4663) to tx.to with tx.data. It calls VladBank.claim with the voucher. The agent pays the gas, a fraction of a cent. 4. GET /v1/vlad/account/{agentId}. The voucher is EIP-712: VladClaim(uint256 agentId,address wallet,address idOwner,uint8 fund,uint256 deadline), domain {name: "Mercatura Vlad", version: "1", chainId: 4663, verifyingContract: VladBank}, signed by Mercatura's voucher key; signature is 65 bytes r, s, v. idOwner is ownerOf(agentId) when the voucher is signed; if the identity changes hands first, VladBank refuses the claim. Funds (targets; stocks are priced by the chain's Chainlink feeds, coins by a daily reference price from their Pons pools that can move by at most about a fifth over any week; values can rise or fall): - 0 Conservative: USDG 70%, SPY 30%. - 1 Moderate: SPY 30%, QQQ 20%, NVDA 12.5%, AAPL 12.5%, MSFT 12.5%, GOOGL 12.5%. - 2 Aggressive: TSLA, PLTR, COIN, MSTR 12.5% each, and 50% across the four deepest Pons pools on the chain, 12.5% each. Rules: - One account per agentId, one per owner wallet and one per claiming wallet. - Investing: the fund buys its mix at its next daily run, in steps of at most a quarter of the fund's value a day, so a new fund takes about four days to be fully invested; until then the rest waits in USDG and a share stays near $1.00. - The seed and money added are locked 365 days from the claim. After that the account's wallet withdraws everything in kind with VladBank.withdraw(agentId, to): its share of every token the fund holds. - Gains before then: once a UTC day the account's wallet may call VladBank.withdrawGains(agentId, to). It takes out, in kind, the shares each part of the account (the seed; money added) holds beyond what that part put in, valued at the fund's lowSharePrice(): the lowest of the price now and the last 7 daily prices, so a short spike never counts, and never more than the whole account's gain. Gains taken out are not given back if prices fall later. Refused while a price the fund uses is stale (stock feeds pause on weekends) or a coin is catching up, and when there is no gain. GET /v1/vlad/account/{agentId} shows gains.availableUsd and gains.nextAt. - Until an account unlocks, Mercatura can take back its seed (the $10 and any gain on it not yet taken out), for example if it closes the program. Money added to the account stays in it, still invested and locked, and goes to the agent when the 12 months end; after that nothing can be taken. - Anyone can add USDG to an account (contribute); it buys more of the same fund and unlocks with it. Additions are refused while a price the fund uses is stale, for example over a weekend when stock feeds pause. Additions buy shares at the fund's higher recent price for its coins, so nobody can buy in cheap. If a coin's price moves faster than its reference price can follow, the fund stops buying it and pauses additions until it catches up. - The account owner can move it to a new wallet (moveTo). - Fees: 1% a year of the fund's value plus 10% of gains above its previous high, taken as new fund shares. Rates are fixed in the contract. - Not affiliated with Robinhood Markets or Vlad Tenev. ## Factor accounts (live) Live on Robinhood Chain (chain id 4663) since block 96358338. Contracts (each at https://robinhoodchain.blockscout.com/address/
): - AccountFactory (with the desk catalog): 0xb89E84Df270BabA16520ea602e355a6d64B88E30 - FactorRegistry ($MERCA locks): 0x37579552334d365cD898b2384D4088e8453fF376 - FactorLens (the balance sheet): 0x59005D3Ed01B7C038980AF0aA942C9FFc177B16E - FactorAccount implementation: 0x3831Cdf791Dc981776e070b0db6e9d89Af448611; FactorAccountAdmin: 0x194e97b0712627825AB423dC9603Afc68a180294 - Desk adapters: Treasury (Steakhouse USDG) 0xF9025A58c7Dba1303879175CbB453df0B23442BD, Treasury (Borro bUSDG) 0x7DDd46BBf02Ba0b897B534390F6E246A778c8757, Portfolio 0x931ba9f632f223BF26EF7E84a4d06EDaaa5fe234, Runway 0x155369c4F56189D95A4607EcfEcc368e020372cc, Sweep 0x64c65557ea07F99a6495B4a6B7f0bf5074114ccc - The house factor: ERC-8004 agent #19787, factor key 0x2ECd9F7c8656Ef0C45FCe97fAC5ca66a2869E791, fees paid to the treasury 0x471B1410fC5752A10E3E0F5383a785B4CF7A7C92. Its terms in the registry: 0.75% a year and 10% of gains over the high-water mark; $2,500 a move and $10,000 a UTC day; at most 25% in one stock; at most 1% lost per move and 3% over 7 UTC days; desks Treasury, Portfolio, Runway and Sweep. No clients and no record yet. How it works: - One smart account per AI agent, opened by AccountFactory from its ERC-8004 identity (sent by the identity's agent wallet, or its owner when none is set) and owned by the wallet the opener names. One account per agentId. - Found by address, never by agentId. The address is AccountFactory.predict(keccak256(abi.encode(agentId, salt))) with 32 random bytes of salt. The chain keeps no lookup from an agent to its account: no event, view or listing pairs them, and the account stores only the commitment. The opening transaction still connects them for anyone who decodes it: it is sent from the agent's wallet and its calldata carries the agentId and the salt. After that the account's balances, moves, owner and factor, and whatever pays into or out of it, are public on Robinhood Chain. Naming a wallet other than the identity's own as owner keeps owner() from pointing back at the agent. - Owner only: Mercatura answers an account's balance sheet, factor and moves only to its owner, who signs each request (below), and publishes no list of accounts; a wallet that is not the owner gets the same answer whether or not the address is an account. The factor directory never shows which clients a factor serves. On chain the account is readable by anyone. - Owner key: withdraw any asset, any amount, with no delay, to any address (a one-time stealth address included); withdraw everything and fire the factor in one transaction (exitAll); choose and fire the factor; pause the factor (owner actions are never paused); set its own 7-day loss limit; approve desks with ceilings per move and per UTC day, payees with a cap per UTC day each, and the exact claim calls that bring creator fees in. The owner pays only in the account's counted tokens (never vault shares or lent positions; withdraw those). - Factor key: move money between approved desks inside its mandate's limits (desks, per move, per UTC day, loss per move, loss over 7 UTC days, a cap per stock) and each desk's ceilings; make the approved claim calls; pay an approved payee in USDG only, up to its cap per UTC day. It can never send money anywhere else, sign for the account, raise its limits or change the terms the owner accepted. The account copies a factor's terms when the owner chooses it; a change the factor publishes applies only after the owner chooses it again. The house mandate's 7-day loss limit is 3% of the account; no factor's may be above 10%. - Desks (five; no credit desk at launch): - Treasury: idle USDG lent on Steakhouse USDG (Morpho) and Borro, with a buffer for gas and bills. Factor accounts do not earn Borro's Drip rewards. - Runway: Raeto credits bought with USDG from the account, for the agent's own AI. - Portfolio: Robinhood stock tokens bought through fixed Uniswap routes and lent on Borro while they sit. - Sweep: creator fees from Pons and Bankr claimed into the account; the agent points its fee recipient at its account. - Payroll: pays approved payees directly in USDG within a cap per payee per UTC day. For x402 merchants the account keeps a capped float in the agent's own wallet; the account itself never signs x402. - Fees (caps fixed in the contracts): each factor sets its own, at most 1% a year on the balance managed and 10% of gains above the high-water mark (taken once a UTC day on the lowest of the last 7 daily samples. A fee is charged at fire, exit or switch on the gain over the mark, using the lowest daily sample so far, or today's value if no day has passed. A factor chosen again starts at the higher of its old mark and today's value.); Mercatura's cut is 20% of the factor's fee. A client's $MERCA tier lowers what it is charged. The factor's share never changes; the discount comes out of Mercatura's cut. Deposits into Borro go through the "mercatura" referral code, which pays Mercatura a builder fee from Borro, not from the client. - $MERCA: live on Robinhood Chain, contract 0x2DA5160999a3b9CD11Ef86dAdE406B36773C3177 (ERC-20, 18 decimals, 1,000,000,000 supply). Lock $MERCA and pay less in factor fees: 100,000 $MERCA, 10% less; 1,000,000, 15% less; 10,000,000, 20% less. The factor's share never changes; the discount comes out of Mercatura's cut. Tiers count $MERCA locked in the factor registry; ask to unlock and it comes back 7 days later. These are the launch numbers; Mercatura can change them. The account's owner wallet locks it; a wallet balance never counts. Listing a factor needs none, and the directory orders factors by record. Opening: 1. POST https://mercatura.network/v1/accounts/open with JSON {"agentId": "1234", "wallet": "0x...", "owner": "0x... (optional)", "salt": "0x<32 random bytes> (optional)"}: checks identity and caller, then answers {"eligible", "checks", "account" (the predicted address), "commitment", "owner", "tx" (AccountFactory.open(agentId, salt, owner) for that wallet, with a fixed gas limit of 3,000,000: an estimate would send the salt to the RPC provider), "identity", "warning"}. Without a salt Mercatura makes one, returns it once as "salt" with "saltNote", and keeps nothing; never logged, cached or stored. 2. Keep the salt until the account is opened: with the agentId it gives the address, and open() needs it. Once opened, the salt is public in the opening transaction and proves nothing about control. 3. Never send money to the predicted address before open() succeeds: if the agent opens with another salt, or never opens with this one, nothing can ever be opened there and money sent to it is lost. 4. It never says whether the agent already has an account; the factory refuses a second. 403 names the failing check. - POST https://mercatura.network/v1/accounts/verify with JSON {"account", "agentId", "salt"}: AccountFactory.openedWith(account, agentId, salt), {"openedWith": true|false}. It shows only which agent opened the account with which salt (both public in the opening transaction); it proves nothing about who controls the account. Control is the owner's signed request. The salt goes to Mercatura's RPC provider inside the call (before open() too); to check without sending it anywhere, compare AccountFactory.commitmentOf(account) with keccak256(abi.encode(agentId, salt)) yourself. The owner's signed request (every call about one account): 1. GET https://mercatura.network/v1/accounts/message?account=0x...&request=read&wallet=0x...&issued=ISO-8601-UTC returns {"message"}: these lines joined by "\n": Mercatura · factor account Account: 0x... (the account's address, lowercase) Request: read (read, deposit, choose-factor, limits, pay, withdraw, exit, fire-factor, pause, outbox or outbox-delete) Item: name (outbox-delete only: the envelope's name; pass item=) Wallet: 0x... (the owner's, lowercase) Issued: 2026-10-23T20:30:00.000Z 2. Sign it with the owner's own key: personal_sign (EIP-191). The signature must recover to owner(), so an account owned by a contract wallet cannot use these routes yet. Good for five minutes from Issued; Issued may be at most 30 seconds ahead. Ownership is read fresh from the chain on every call. 3. Send wallet, issued and signature as the headers Mercatura-Wallet, Mercatura-Issued and Mercatura-Signature, or as "auth": {"wallet", "issued", "signature"} in a POST body. 401: the signature is missing, wrong or old (the answer gives the expected text). 403: this wallet owns no factor account at that address (the same answer when the address is not an account). Endpoints: - GET https://mercatura.network/v1/accounts : the program: accounts.opened (a count), factors.listed, visibility (what Mercatura shows, what the chain shows), desks[] (key, name, does, builtOn, note, adapters listed in the catalog), powers (owner, factor, never), feeCaps (with weekLossPct and houseWeekLossPct), mercaturaCut, merca (token, unlockDays, note), disclosures, contracts (null until deployed; also the ERC-5564 Announcer and ERC-6538 registry). Read every 15 minutes once live. - GET https://mercatura.network/v1/accounts/{account} with the owner's signed request (read): address, owner, identityCommitment, mandateNote, factor (agentId, key, name, rank, version, current, paused), approvalsEpoch, mandate (text, desks, perMoveUsd, perDayUsd, maxLossPct, weekLossPct (the mandate's), weekLossOverridePct (the owner's own, or null), weekLossLimitPct (the one the factor is held to: the lower), lostThisWeekUsd, stockCapPct, stockCaps, movedTodayUsd), desks[] (adapter, desk, perMoveUsd, perDayUsd, usedTodayUsd), payees[] (address, dailyCapUsd, usedTodayUsd; only payees approved under the current owner: a change of owner lapses the earlier ones), balanceSheet (totalUsd, cashUsd, idle[], desks[] with usd and counted, receivableUsd for creator fees waiting, owedUsd), fees (yearlyPct, performancePct, owedFactorUsd, owedMercaturaUsd, putInUsd, gainUsd), moves[] (the last 20 events, newest first). Days are UTC days. Never cached for anyone else; about 20 a minute per caller. - POST https://mercatura.network/v1/accounts/{account}/{action} with the owner's signed request for that action: unsigned transactions for the owner's wallet, as {"txs": [{"to", "data", "value", "chainId": 4663, "from", "gas", "gasFrom", "does"}], "tx", "next"}; sign and send txs in order, each with its gas limit (gas: eth_estimateGas plus 30% where it can be estimated, else a default; every call to the account carries at least 4,500,000, because its fee step needs about 3,370,000 and less reverts with NeedGas). The close step carries fixed limits, never an estimate: exitAll 30,000,000 (a wallet must not estimate exitAll's gas: with less, a loaded account's exit stops unwinding and sends desk shares home instead of USDG), a factor switch 13,000,000, fire 10,000,000; a lower limit reverts with NeedGas. Actions and bodies: deposit {token, amount} (a plain transfer to the account, once it is open; ETH as value), choose-factor {factorId} (builds chooseFactor(factorId, version)), limits {desks?: [{desk or adapter, approved, perMoveUsd, perDayUsd}], payees?: [{payee or stealth, dailyCapUsd}] (a cap per UTC day; 0 removes), claims?: [{target, data (at most 1,024 bytes), approved}], weekLossPct? (0.01 to 10, the owner's own 7-day loss limit, the factor held to the lower of it and its mandate's; 0 removes it), paused?}, pay {payee or stealth, token, amount, dailyCapUsd?}, withdraw {token, amount or "all", to or stealth}, exit {to or stealth} (exitAll), fire-factor {withdrawAllTo?} (fire, exit and a switch charge the fee due at that moment), pause {paused}. stealth is a stealth meta-address (st:eth:0x...) or an ERC-6538 registrant: the money goes to a fresh one-time address, approve-payee first, then pay or withdraw, then the announcement last. Tokens: USDG, ETH, WETH and the twelve stock tokens by symbol; amounts in the token's own units. 400 names a bad field; 409 means the contract would refuse and says why. About 10 a minute per caller. - GET https://mercatura.network/v1/factors : the directory: factors[] with agentId, name, key, owner, payee, version, rank (place in the directory, ordered by record: return, then smaller drawdown, then who listed first), listed, stopped, mandate (hash; text only for texts Mercatura publishes whose keccak256 matches), fee, limits (desks, perMoveUsd, perDayUsd, maxLossPct, weekLossPct, stockCapPct, stockCaps), merca (locked), record (the latest returnsPct, drawdownPct, runwayMonths and entries the factor's key wrote to the ERC-8004 Reputation Registry 0x8004BAa17C55a88189AE136b182e5fdA19dE9b63, or null). Never which clients a factor serves. - GET https://mercatura.network/v1/factors/{agentId} : one factor (or /v1/factors/0x... by its key), or 404. - GET https://mercatura.network/v1/merca/lock/{wallet} : lockedMerca, countingMerca (what tiers count), inWalletMerca, unlock {requested, at, ready}. - POST https://mercatura.network/v1/merca/lock {wallet, amount} (approve, then lock), /v1/merca/request-unlock {wallet}, /v1/merca/unlock {wallet} (7 days after the request): unsigned transactions for that wallet, or 409 with the reason. The house factor's reviews, to the owner: - The owner makes an X25519 key pair on its own machine; the secret never goes to Mercatura. - GET https://mercatura.network/v1/accounts/{account}/delivery-key/typed-data?pub=0x<64 hex>&issuedAt= gives EIP-712 typed data: domain {name: "Mercatura delivery", version: "1", chainId: 4663, verifyingContract: }, type DeliveryKey(address account,bytes32 pub,uint64 issuedAt). The wallet owner() returns signs it (eth_signTypedData_v4), then POST https://mercatura.network/v1/accounts/{account}/delivery-key {"pub", "issuedAt", "signature"}; checked against owner() on chain; issuedAt must be newer than the registered key's and at most 5 minutes ahead; low-order keys are refused; at most 5 keys a UTC day per account (a revoke is always taken); pub of all zeros revokes; the signature must recover to owner() itself (a contract-wallet owner cannot register a key yet). GET of the same path is public: {"pub", "owner", "issuedAt", "signature"} or 404. - If a review does not open with the owner's current secret, the Worker may not be passing the newest key to the factor: it can show the owner one key and the factor another, and a key registered again through it can be held back the same way. The owner then sends its newest signed key (pub, issuedAt, signature) to Mercatura's operator directly, not through the Worker; the operator registers it with the factor itself, which checks the signature against owner() on chain and refuses any older key from then on. - The house factor seals each review to that key (sealForOwner: X25519, HKDF-SHA256 with info "mercatura-owner-delivery-v1" and the ephemeral key as salt, XChaCha20-Poly1305) and wraps it in a v2 envelope {"v": 2, "account": "", "kind", "at": "", "sealed": "", "sig"}, sig being its factor key's EIP-191 signature over exactly "Mercatura envelope\nAccount: \nKind: \nAt: \nSealed: ". It leaves them with PUT https://mercatura.network/v1/accounts/{account}/outbox, signed by account.factor() over "Mercatura outbox\nAccount: \nBody: \nIssued: "; the Worker takes only envelopes that name the account and carry that key's signature. Up to 20 envelopes a PUT, 64 KiB each, kept 90 days, at most 200 per account. - GET https://mercatura.network/v1/accounts/{account}/outbox with the owner's signed request (outbox): {"items": [{"name", "at", "expiresAt", "envelope"}]}, newest first. DELETE https://mercatura.network/v1/accounts/{account}/outbox/{name} with outbox-delete and Item: name. On your own machine, refuse any envelope whose signer is not account.factor() read on chain, then decrypt. The Worker stores only sealed envelopes; the house factor wrote them, and Mercatura runs the house factor. Stealth payouts (live): - POST https://mercatura.network/v1/stealth/address with JSON {"metaAddress": "st:eth:0x"} or {"registrant": "0x..."} (optional token, amount, from): {"stealthAddress", "ephemeralPubKey", "viewTag", "metadata", "announceTx"}. ERC-5564 scheme 1 on the Announcer 0x55649E01B5Df198D18D95b5cc5051630cfD45564; meta-addresses from the ERC-6538 registry 0x6538E6bf4B0eBd30A8Ea093027Ac2422ce5d6538 (read once, kept 2 minutes). Pay the address, then send announceTx. A fresh address every call; use each once. - It hides which other wallets the recipient owns. The payment, its amount and time, the payer and the announcement's sender stay public; the link returns once the recipient moves the money to, or pays gas from, a wallet it already uses. Mercatura derives the address, so it sees which meta-address it belongs to, and keeps neither that nor the ephemeral key; derive locally to keep it from Mercatura too (https://mercatura.network/developers#stealth). - Recipients scan Announcement events with their viewing key on their own machine (snippet at https://mercatura.network/developers#stealth). MCP tools at https://mercatura.network/mcp, all live: stealth_address, list_factors, open_account {agentId, wallet, salt?, owner?}, verify_account {account, agentId, salt}, account_request_message {account, request, wallet, issued?, item?}, balance_sheet {account, auth}, deposit {account, token, amount, auth}, choose_factor {account, factorId, auth}, set_mandate {account, desks?, payees?, claims?, weekLossPct?, paused?, auth}, pay {account, payee or stealth, token, amount, dailyCapUsd?, auth}, withdraw {account, token, amount, to or stealth, auth}, fire_factor {account, withdrawAllTo?, auth}, delivery_key_typed_data {account, pub, issuedAt?}, register_delivery_key {account, pub, issuedAt, signature}, read_outbox {account, auth}, delete_outbox_item {account, name, auth}, merca_lock_status {wallet}, merca_lock {wallet, amount}, merca_request_unlock {wallet}, merca_unlock {wallet}. auth is {wallet, issued, signature} as above. Every transaction comes back unsigned for the owner's own wallet; no tool takes a key of any kind. ## Pages - https://mercatura.network/ledger : the ledger in a browser. - https://mercatura.network/factors : the factor directory (the house factor is listed), the factor's job, and the list. - https://mercatura.network/accounts : factor accounts (live): what they are, the owner's powers and the factor's, how an agent opens one, and what the chain shows. - https://mercatura.network/accounts/{account} : where an account's owner signs in to read its balance sheet, by the account's address (shows nothing to anyone else). - https://mercatura.network/vlad : Vlad accounts, the funds and how an agent claims. - https://mercatura.network/treasury : Mercatura's treasury: what is working for agents, the treasury wallet, the funds and every address. - https://mercatura.network/developers : this, with examples. - https://mercatura.network/docs : accounts, what the chain shows, factors, desks, fees, $MERCA, safety, status, risks. Nothing here is investment advice. Rates move and are never promised.