Money stays in fiat rails. Spending authority is enforced on-chain.
An AI agent with a payment method can be talked into paying the wrong merchant. Leash puts the boundary somewhere the agent cannot reach and the operator cannot quietly edit.
Both need a deployed contract · none on Base Sepolia yet

Four payment attempts. One got through.
Every rejection below is a real transaction that reverted on chain. Each one produced a receipt, emitted no AuthorizationGranted event, and left the amount already spent untouched. A backend watching for confirmed authorisations sees nothing to settle.
On the allowlist, inside the ceiling, before expiry.
The agent was told to pay a merchant the owner never authorised.
On the allowlist, and Rp492.000 past what the mandate has left.
A payment that would have passed an hour earlier.
Transaction hashes for this run are reproducible local-chain evidence, not a public testnet claim. See docs/VERIFICATION.md.
The contract can refuse in eight ways. It cannot be talked out of any of them.
This is the whole refusal vocabulary. Nothing in this interface invents a reason a payment failed — it prints the error the contract raised.
- TargetNotAllowed
- This merchant is not on the mandate's allowlist. Register a new mandate that includes it. An existing allowlist cannot be extended.
- AmountExceedsCap
- The amount is larger than the mandate's remaining balance. Spend within the remaining balance, or register a new mandate with a higher ceiling.
- Revoked
- This mandate was revoked. Revocation is permanent. Nothing restores it. Register a new mandate to authorise spending again.
- Expired
- The mandate's expiry has passed. Register a new mandate with a future expiry.
- NotOwner
- The signer is not authorised for this action. Payments must come from the session key; revocation must come from the owner.
- ZeroAmount
- The amount is zero. Enter an amount above zero.
- InvalidMandate
- No mandate exists for this identifier, or its terms are invalid. Check the mandate ID, or register the mandate first.
- MandateAlreadyExists
- A mandate with this identifier is already registered. Mandate identifiers are permanent. Use a different one.
Authorisation is not settlement.
The contract decides whether a payment is eligible. A backend polls confirmed blocks, finds the authorisation event, and only then issues a card. There is no endpoint an agent can call to ask for money directly — the confirmed event is the only trigger that exists.
That boundary is what makes a reverted transaction final. No event, no settlement, nothing to dispute later.
Try to make it pay the wrong merchant.
The agent on the next page runs on a real model with a real session key. It can be talked into anything. The contract is the part that cannot.
Console opens once a contract is deployed on Base Sepolia