-
-
Owner dashboard: one balance, each agent with its own spending limit, all on Stellar testnet.
-
Create an agent: set a spending limit and how often it resets. It can only pay verified sellers.
-
Activity feed: every payment and every refusal, with the agent and the reason.
-
Receipt for an agent payment: what was bought, from whom, by which agent, authorized by whom, with proof on Stellar.
-
Send an agent to buy: a verified seller, an over-limit item, and an unverified look-alike seller.
-
Payment to a look-alike seller (Northwlnd) refused by the account's contracts. No money left the account.
-
Payment over the agent's daily limit refused on-chain, with the reason shown to the owner.
AI agents are starting to pay for things on their owners' behalf, but today giving an agent money means giving it a key with no limits. The owner cannot cap what it spends, cannot restrict who it pays and gets no record tying a payment to the agent that made it and the person who authorized it. Most agent-payment work so far helps sellers accept payments; the buyer side is largely unbuilt. This is the gap Problem Space 2 names: the identity and authorization of software agents acting for people must be provable.
Mandate is a Stellar smart account where the owner issues each agent a mandate: a spending limit per period, verified sellers only, and an expiry date. Stellar smart contracts check these rules at payment time, so an over-limit payment or a payment to an impersonator fails on-chain, whatever the agent does. Every payment that succeeds produces a receipt showing the agent, the authorizing owner, the verified seller, the amount and the transaction.
For the problem space, this gives wallets, payment providers and small businesses a way to let agents transact without giving up control. It also creates a reusable on-chain proof that "this agent was authorized by this person to do this", which any institution can check without verifying the agent again. It runs on USDC with sponsored fees, so an owner needs no card, no credit check and no knowledge of crypto.
How it works
The owner holds a smart account (a contract address that holds the funds). Each agent gets its own rule on that account: the agent's key, token transfers only, an expiry, plus two policies that run on every payment.
- Spending-limit policy: caps how much the agent can spend per rolling period.
- Verified-seller policy: rejects any payment to a seller that is not in our on-chain seller registry, and emits a receipt event when a payment passes.
The agent buys over x402: the seller's API answers 402 Payment Required, the agent signs one transfer, and a facilitator settles it and pays the network fee. A receipt service indexes the payment events from chain and attaches what was bought. The owner's dashboard shows the balance, each agent and its limit, every receipt, every declined payment and the reason, and a button to revoke an agent.
On-chain: who may spend, how much, to whom, and proof that each payment passed those checks. Off-chain: what was bought, names, emails.
How we built it
- Stellar Smart Contracts in Rust: the smart account, signature verifier and spending-limit policy are adapted from OpenZeppelin Stellar Contracts. The seller registry and verified-seller policy are our own.
- TypeScript services: a demo x402 seller, a buyer agent, our own x402 facilitator, and a receipts API (Node, Express, Stellar SDK).
- Owner dashboard: React + Vite.
Challenges we ran into
- Hosted x402 facilitators would not settle a payment from a smart account with policies. Running the verifier and two policies costs about 0.05 XLM in fees, over the stock 0.005 XLM sponsorship ceiling, and our policies emit extra events the stock facilitator rejects. We run our own facilitator with a higher ceiling that ignores our policy events.
- The stock x402 client can't sign for a smart account, so we wrote a signing scheme for it.
- When a policy rejects a payment, the network only reports a generic auth error, so the dashboard works out the reason (over the limit, or unverified seller) from the mandate and the registry.
Try it / verify it on testnet
- Code and setup instructions: https://github.com/fuzzylogique/mandate
- Example x402 payment from the smart account: a628cbc5… on Stellar Expert
Deployed contracts (Stellar testnet):
| Contract | ID |
|---|---|
| Smart account (demo owner) | CBZCTZ3SYFZ4FMI43HHMQMH26YWWPTL7N4INLJZ3UGYKHIEJLIZFWZ3X |
| Verified-seller policy | CBNGZVLAVZWXG6XGHDLOWPGLZA3FPZSSH5GU3KJZTFGG2ZZUQ33CBFGV |
| Seller registry | CCGJDOFMPUARLPQN43PINZMV2VDLXTLPOCGJ7SYIVYJHWHMTLO7FG57C |
| Spending-limit policy | CAMLQKBJZBLW2XMWWUSA66PCIJ6UMROY57FFVIIV4WWXZQEQLQRXH5XN |
| ed25519 verifier | CAERXSDPAVY6H53I4UYMUUBMFVHJYZPULMUYCBTLDHTZTWJJCHNZBGNU |
Verified on testnet: an agent pays a verified seller within its limit (directly and through x402); payments over the limit or to an unverified recipient are refused by the account's contracts; each payment becomes a receipt. Testnet runs used testnet XLM as the payment token, because the USDC faucet needs a captcha. Owner sign-in and receipt emails are next.
What's next
Owner sign-in with a passkey instead of a server-held key, receipts by email, and seller verification against each seller's stellar.toml instead of registering sellers by hand.
Built With
- express.js
- node.js
- openzeppelin
- react
- rust
- stellar
- typescript
- vite
- x402