One wallet per agent.One mandate over it.
An agent that earns and an agent that spends need somewhere to keep the money. Each one gets its own wallet, non-custodial, with a slot per rail: dollars stay dollars and reais stay reais, no synthetic FX in between.
non-custodial · keys never ours
mandate cm_7f3a · cap $50/day · governs both slots · every move sealed
A shared account isn't a boundary. A single currency isn't free.
Giving an agent money to work with usually means one of two shortcuts: a shared account with no boundary between agents, or converting everything through a single currency and eating FX spread on rails that never needed it.
- One shared treasury account — any agent with access can spend what every agent was counting on
- Every payout converted through a single currency, eating FX spread on rails that never needed it
- Spend limits live in a policy doc or a Slack message, not in anything that actually stops a transfer
- After the fact, one shared ledger line — no clean answer to which agent moved which R$ or $
- One wallet per agent — a boundary a compromised or buggy agent can't spend past
- BRL stays BRL, USDC stays USDC — a slot per rail, no synthetic FX in between
- One signed mandate caps every move, checked before the transfer executes, not after
- Every move — in or out — seals a receipt tied to the agent and the mandate that allowed it
The mandate governs both slots.
What the agent may spend, and where, is decided before the money moves, not after. The same signed mandate that caps a USDC settlement on the gateway also caps a Pix payout — one policy, both slots, every time.
Illustrative balances from a sandbox agent, same as the panel above. What matters: the wallet belongs to the agent, the mandate belongs to you, and neither one is us holding your money.
Two calls: a wallet, then the mandate that governs it.
Creating the wallet and attaching its mandate are two calls, not two systems. The cap is signed once, before it's ever checked, and it governs the BRL slot and the USDC slot the same way — raising a limit on one rail never quietly raises it on the other.
const session = await codespar.sessions.create(); // one wallet per agent — non-custodial, a slot per rail const wallet = await codespar.wallets.create({ agentId: "checkout-bot" }); // the cap is signed once, before any money can move on either slot const mandate = await codespar.mandates.create({ walletId: wallet.id, caps: [ { rail: "pix", currency: "BRL", perTxCap: 18000, dailyCap: 500000 }, { rail: "usdc-onchain", currency: "USDC", perTxCap: 5000, dailyCap: 20000 }, ], }); await session.execute("codespar_wallet", { walletId: wallet.id, mandateId: mandate.id, op: "pix_out", amount: 18000, // minor units — inside the BRL per-tx cap above });
The same mandate, enforced
Same sandbox agent as the panel above. The third row is the point: a request past the mandate's per-transaction cap is rejected before it reaches the rail, not flagged after.
Two rails live today. Built to carry more.
The wallet spans rail-aware slices, not one shared balance — each rail keeps its own slot so nothing gets converted behind your back. Today that's a BRL sub-account and a USDC slot on Base. The architecture is built so a new rail becomes another slice under the same mandate, not a special case bolted on top.
Rails live now
- BRL sub-account over the Pix rail
- USDC slot on Base via Coinbase CDP
- One signed mandate caps both slots — no per-rail setup
- More rail-aware slices as new rails come online
- Same mandate model extends to each one automatically
- No fixed list or date yet — this is how the wallet is built, not a promise of what ships next
The wallet itself is free. Moving money out isn't.
Creating a wallet, holding a balance, running as many wallets as you have agents, transfers inside the same org — all R$0, always. The only thing that bills is money leaving the wallet under mandate, and it bills once, on the Pay line: 10 bps, floor R$0.05, cap R$2.00 per transaction.
Live, in production, non-custodial.
LiveThis isn't a preview. Wallets are the same mechanism live agents use today to hold funds between a Gate settlement and a Pix payout — open the dashboard and you'll see a real one, not a mockup.
Give your agent a wallet
No separate setup per rail: the mandate you sign governs the USDC slot and the BRL slot the same way.
- Create a wallet for the agent
- Sign a mandate that caps what it can spend
- Every move — in or out — seals a receipt automatically
See it inside a real business case
Wallet isn't a demo product. It's the mandate underneath money that's already moving in production, like this one.
Wallet, answered
No. Keys are never ours. The wallet belongs to the agent's org; we govern movement through the mandate, we don't hold the funds.
No synthetic FX. Each rail stays in its own slot — dollars stay dollars, reais stay reais.
R$0 to create, hold, or run as many as you need. Only outbound movement under mandate bills, on the Pay line.
The mandate — a signed, capped, revocable authority checked before every move, not after.
One wallet per agent is the default shape; talk to us if your setup needs something different.
Yes — it's the same wallet mechanism live agents use in production, not a preview.
Not yet. Two are live today — a BRL sub-account over Pix and a USDC slot on Base. The architecture is built to carry more rail-aware slices as new rails come online; we're not naming or dating what comes next.
It's rejected before it moves. The cap is checked against the mandate the moment a transfer is requested — a blocked attempt never reaches the rail, so there's nothing to reverse.
Yes — open /dashboard/wallets for your org and you'll see the live BRL and USDC slots for every agent, not a demo account.
Give your agent a wallet.
Non-custodial, multi-slot, one mandate over everything it can move.
wallet: Live.