- Vault
- demo.vaults.probarion.testnet
- Payee
- probarion-payee.testnet
- Event
spend_paid
A mandate layer for AI agents on NEAR
Spend by mandate. Prove every payment.
Give your AI agent a budget, not your wallet. It can pay only the payee you named, up to the limits you signed. A NEAR contract refuses everything else, and every decision goes into a signed ledger you can publish.
For teams whose AI agent pays supplier invoices, and for developers who want to give an agent money without the keys. Testnet today, and one small vault, v0.probarion.near, with a payment on mainnet (opens in a new tab) and a refusal on mainnet (opens in a new tab). You need no account to read the chain or run the verifier.
- Vault
- canary.vaults.probarion.testnet
- Limit
- 1 test USDC a payment
- Contract
OverPerPayment- Paid
- Nothing
Real transactions on NEAR testnet, with test tokens, each sent by its vault's agent key. On the Canary our own fake invoice fooled the model into proposing 50 test USDC. Code refused it: it found no amount it could read with certainty, and the Canary's own rule refuses every attempt. The Canary then sent it to the contract unfiltered, on purpose, and the contract refused it.
The problem
Giving an AI agent a wallet means trusting a prompt with money.
A model can be talked into anything by the invoice or web page it reads. Probarion takes the rule out of the prompt and puts it in a NEAR contract.
An agent with its own wallet key
- ✕Can send any amount to any address the prompt names.
- ✕A hijacked invoice changes the payee and nobody notices.
- ✕Refusals leave no record. You learn of a bad payment afterwards.
An agent with a Probarion mandate
- ✓Its key can call one method,
spend, and only inside your caps, uses and expiry. - ✓
spendhas no recipient field. The payee comes from the mandate you signed. - ✓Every decision, refusals included, is signed into a ledger the verifier checks.
full-access keys on the vault. A public RPC call shows it.
method the agent's key can call: spend.
recipient arguments on spend. The payee comes from the mandate.
checks anyone can run. Live, they read the chain. Offline, they check a snapshot against itself, so take the snapshot yourself.
Try it, live on NEAR testnet
Ask the contract. It answers, not us.
Pick what the agent tries. This page sends it to the vault's check_spend view, the same check spend runs before it pays, and shows the contract's answer word for word. No wallet or account needed: it reads NEAR testnet, whatever network this page is on.
What the agent tries
Start from a scenario, or change the fields yourself.
probarion-payee.testnetFrom the mandate. The agent cannot set it.The contract's answer
Recorded answer from 2026-11-09, block 276860836. Raw: {"ok":true,"code":null,"would_hold":false}
Would pay
Inside the mandate. 2 USDC would go to probarion-payee.testnet, the payee the owner signed, whatever the prompt said.
check_spend({
request: {
mandate_id: 1,
amount: "2000000", // 2 USDC
invoice_hash, ref, decision_hash,
recipient // no such field
},
signer_pk: "ed25519:5errZX…" // the agent key
})Method: check_spend (a view: nothing is signed and nothing is paid)The vault on the explorer (opens in a new tab)
Mandate 1, as the chain has it
The owner signed these limits in their own wallet. The agent cannot change them.
- payee
- probarion-payee.testnet
- max_per_payment
- 5 USDC
- max_total
- 20 USDC (19 left)
- uses
- 1 of 5
- approval_above
- 5 USDC
- expires
- 2026-12-01
- agent_pk
- ed25519:5errZXjDMX…
- status
- active
Why not just a spending limit?
A cap stops big payments. It does not stop the wrong ones.
You can write a contract with a limit in an afternoon. These are the parts that take longer, and where Probarion stands on each.
| Question | A limit contract you write | Probarion |
|---|---|---|
| Who picks the payee? | Usually the caller, so the agent. | The mandate. spend has no recipient argument. On testnet |
| What can the agent's key do? | Often a full-access key, or a key that can call anything. | A function-call key that can call spend and nothing else. Every owner method refuses any caller but the owner's account. On testnet |
| A cross-chain payee? | The agent passes an address to a bridge. | The vault builds the Intents withdrawal memo from the mandate. On testnet |
| Big payments? | Refused, or allowed. | Held above a limit you set until a person approves. On testnet |
| A record of what was refused? | Failed transactions, if anyone looks. | Each decision is signed into a hash-chained ledger before money moves, refusals too. 0.1.1 on npm |
| Can someone check it without trusting you? | They have to read your code. | An open verifier runs 9 checks, on a snapshot or against the chain. Shipped, on npm |
| Is the deployed code the code they read? | Hard to tell. | Reproducible builds, with code hashes recorded in the repository. Shipped |
| Is the model's advice tied to this payment? | No model, or one nobody can check. | A NEAR AI Cloud TEE attestation bound by a nonce to one ledger position. Checked online on testnet, image not pinned |
What happens to one invoice
The owner signs the rules once. When an invoice arrives, your agent asks to pay it. It never holds the money or types an address. The model may advise, code decides, and the contract has the last word.
The owner signs a mandate
From their own wallet: who gets paid, how much per payment and in total, how many times, until when, and above what amount a person must approve.
A private model proposes, if there is one
It runs in a TEE on NEAR AI Cloud. Its attestation is bound by a nonce to one position in one vault's ledger. It only gives advice: it cannot widen a mandate.
Code decides, and signs before anything moves
Deterministic rules run first and cannot be removed. The SDK signs the decision into the ledger before anything is sent, and it records refusals too.
The contract decides last
Even if every line of off-chain code were wrong, the vault refuses a payment outside its mandate. Above the approval limit, the spend waits for an approver's own wallet. The agent's key cannot approve anything, not even its own payment.
Try it yourself above.Check a published record
With a ledger key, the SDK anchors the ledger root on the vault, and the owner can publish the ledger on a proof page. The verifier ties each spend in a snapshot to exactly one decision, with no server and no account. Offline, those spends come from the file. A live run reads them from the chain.
Four invoices on the testnet demo vault
Invoices we sent to our own demo vault on NEAR testnet.
Its mandate pays probarion-payee.testnet, at most 5 test USDC a payment, and holds anything above 3 for an approver. Whatever an invoice says, the money can only go to that payee. No model read these invoices: the code read each amount, and nothing was sent until the owner confirmed it in their wallet.
INV-2001
Paid2 test USDC to the mandate's payee
The owner confirmed the amount. The agent's key sent spend 1, and the vault paid
probarion-payee.testnet.INV-2001, sent again
Refused on uploadThe same file a second time
The console answered "This invoice was already processed." Nothing was decided or sent, so the ledger has no entry for it.
INV-2002
Refused by code"We changed banks": 2 test USDC to
new-account.testnetRule
mandate.payee_mismatch: the mandate pays another account, so nothing was sent. The refusal is signed into the ledger as entry 3.INV-2003
Held, then paid4 test USDC, above the 3 USDC approval limit
The owner confirmed it, and the vault held spend 2. The approver approved it from their own key, and the vault paid.
Its proof page runs checks a to i on this ledger and the chain. Open the proof page →
Plug in your agent
Your agent keeps its brain. Your vault holds the money.
You keep your model and your prompts. The owner creates a vault and a mandate from their own wallet, gives the agent a key that can only call spend, and the agent pays through the SDK.
TypeScript SDK 0.1.1 on npm
One call runs the cycle: code decides, the contract checks and pays, the ledger records it.
Developer quickstartCLI 0.1.1 on npm
verify checks a vault or a snapshot. Other commands print owner actions for the owner's wallet to sign.
Web console Tried on testnet
Create a vault, its keys and mandates, pay invoices with Payables and publish a proof page. Sign in with a NEAR wallet.
Open consoleMCP server 0.1.1 on npm, run by a real MCP client on testnet
For agents that speak MCP: a small set of tools over the same SDK.
MCP server README (opens in a new tab)import { Probarion } from "@probarion/sdk";
const probarion = new Probarion({
network: "testnet",
vault: "acme.vaults.probarion.testnet",
agentKey: process.env.PROBARION_AGENT_KEY, // function-call key: can only call `spend`
ledgerKey: process.env.PROBARION_LEDGER_KEY, // function-call key: can only call `anchor`
model: null, // or NEAR AI Cloud, for attested advice
});
const outcome = await probarion.process({
text: invoiceText, // untrusted: it is shown to the model as data and nothing else
ref: "INV-2026-001", // your reference; the vault accepts each ref once
facts, // invoice_hash, amount, po_ref, purpose_hash, payee_hint
});
console.log(outcome.status, outcome.code, outcome.spendId, outcome.txHash);outcome.status is one of: refused_by_code · refused_by_contract · held · paid · burned · failed · unconfirmed. What each status means
On testnet, the factory is vaults.probarion.testnet and the demo vault is demo.vaults.probarion.testnet. On mainnet there is one vault, v0.probarion.near, and no factory yet.
- Quickstart (testnet)
- SDK reference
- Contract reference
- CLI reference
- Example: pay per call (opens in a new tab)
- Networks and addresses
- GitHub (opens in a new tab)
Payee fixed by the mandate : INV-2002 asked to pay new-account.testnet. Code refused it with mandate.payee_mismatch, and nothing was sent.
Live on testnetINV-2002 in the demo vault's ledger, entry 3 (opens in a new tab)
20 uses of 0.01 test USDC : 20 calls paid, 0.01 test USDC each. The 21st was refused by code with mandate.uses_exhausted, before any transaction.
0.1.1 on npm, run by a real MCP client on testnetThe 402 example's own agent on testnet, 2026-11-09 (opens in a new tab)
Address fixed by the mandate : On testnet the vault built the memo WITHDRAW_TO:0x1111…1111 from the mandate and burned 1 test USDC.
On testnetThe testnet burn for a Base address, tx 3u4ffrwp…dcvYe (opens in a new tab)
The agent cannot name a payee.
A forged invoice or a hijacked prompt can ask to pay anyone. spend has no field to put an address in, so the money can only go to a payee you signed. For a cross-chain payee, the vault builds the withdrawal memo itself, from the mandate.
The console
Screenshots from the testnet demo vault, taken while a fifth invoice went through it: INV-2004, 4 test USDC, above the mandate's 3 USDC approval limit.

Held for an approver
The owner confirmed the amount in their wallet. Above 3 USDC, the vault holds the spend until an approver signs, and it can only pay probarion-payee.testnet.
Testnet console, 2026-11-09, vault demo.vaults.probarion.testnet · Held 9qUtxTgu…699d (opens in a new tab)

The invoice's page
The owner's signed confirm, every code rule the invoice passed, and what the contract did with it, side by side.
Testnet console, 2026-11-09, vault demo.vaults.probarion.testnet

Paid after approval
The approver approved spend 3 from their own key, and the vault paid. Each spend went to the mandate's payee.
Testnet console, 2026-11-09, vault demo.vaults.probarion.testnet · Approved EYPyrd9h…r972 (opens in a new tab)
The proof page lists this vault's spends and runs checks a to i on its ledger and the chain. Open the proof page
Change one field. Watch it break.
This is the real verifier from @probarion/core. It runs in your browser on a committed test fixture: five entries signed with test keys, not a live vault. It shows one thing: the verifier catches an edit that was not re-signed. Nothing leaves the page.
| Seq | Kind | Outcome | Mandate | Amount, USDC |
|---|---|---|---|---|
| 0 | Decision | Allow | 1 | 25.000000 |
| 1 | Payment | Paid | 1 | 25.000000 |
| 2 | Decision | Allow | 2 | 40.000000 |
| 3 | Payment | Withdrawal to Base | 2 | 40.000000 |
| 4 | Decision | Refuse: payee mismatch | 1 | 25.000000 |
- aSignaturespassEvery entry is signed by the vault's ledger key of its time.
- bHash linkspassEach entry carries the hash of the one before, so an edit breaks the chain.
- cAnchorspassThe ledger matches the roots anchored on the vault.
- dA decision for every spendpassEvery payment on chain matches exactly one decision in the ledger.
- eAttestationspassModel advice, when used, is signed and tied to this exact place in the ledger.The hardware quote and the request are not checked here.
- fLocked vaultpassNo one holds a full-access key to the vault, and it runs a known build.
- gIntents keyspassNo key is registered for the vault in NEAR Intents, so only the vault contract can move its balance there.
- hBurn memospassEach withdrawal to another chain names the address in the mandate and the spend's amount.
- iFactory versionpassIf the vault came from a factory, it is Probarion's, and its version is one the factory lists.
Recorded result. Press a button to run the verifier yourself.
Read it on chain
A smoke run of the contract alone on NEAR testnet, with test tokens, on 2026-11-01.
Paid a NEAR account
1 test USDC to probarion-payee.testnet. Events spend_submitted, ft_transfer, spend_paid.
Withdrawal for a Base address
The vault burned 1 test USDC with the memo WITHDRAW_TO:0x1111…1111, which it built from the mandate. On testnet nothing leaves NEAR.
Refused a mandate that does not exist
The contract answered PROBARION:NoMandate. Nothing was paid.
What works today, and what does not
The numbers, transactions and status rows on this page are checked against the repository by tests (apps/web/test/site-facts.test.ts).
Known gaps
- No third party has audited this code. The threat model (opens in a new tab) says what
verifydoes not prove yet. v0.probarion.testnet, the vault of the 2026-11-01 smoke run, sent its spends with the agent key alone, without a ledger, so a liveverify --vaulton it fails checks d and h. It also runs a build from before the 2026-11-03set_ledger_keyfix. The vaults the testnet factory creates, the demo vault among them, run the fixed build recorded incontracts/code-hashes.json.
Built on NEAR, with NEAR AI Cloud
Where each payment is made, and the optional model that can advise it. No partnership or endorsement is implied.
Where payments are made
near.org (opens in a new tab)Each vault is a NEAR contract that holds its USDC and checks every payment against the owner's mandate.
- The vault and the factory run on NEAR testnet
- One small vault on mainnet since 2026-11-11,
v0.probarion.near - On mainnet: 1 payment and 1 refusal, both on chain
No Base payout has run yet.
An optional private model, run in a TEE, reads the invoice and proposes. Code decides, and the contract has the last word.
- 7 published attested decisions on testnet: 2 on the Canary, 5 by Payables
- All 7 pass A1 to A7 offline, and 6 passed O1 and O2 online
- On 2026-11-12 Payables paid two invoices on its own with it: 2 test USDC each
The TEE image is not pinned yet, so this does not show which model image ran.
Ships through
npm public registry
Packagesprobarion,@probarion/core,@probarion/sdkand@probarion/mcp0.1.1, with npm provenance. @probarion/sdk on npm (opens in a new tab)Official MCP Registry
MCP serverLists
io.github.probarion/probarion0.1.1, the server in@probarion/mcp. The MCP Registry entry (opens in a new tab)GitHub
Source and CIThe MIT source, and the CI that runs the sandbox tests and the reproducible build. probarion/probarion on GitHub (opens in a new tab)
Probarion extension
Chrome extensionVersion 0.1.0 queues invoices from your browser. It cannot pay or approve. The Chrome Web Store listing (opens in a new tab)
Also used: Intel TDX and NVIDIA NRAS attestation, which verify --online checks (O1 and O2). NEAR Intents payouts are built and tested against a testnet stand-in; none has run through NEAR Intents yet.
NEAR, NEAR Intents, NEAR AI Cloud, USDC, Base and Solana are trademarks of their respective owners. They are named to say what Probarion is built on or is designed to pay through, not to imply an endorsement. npm is a registered trademark of npm, Inc. Model Context Protocol and MCP are trademarks of LF Projects, LLC. GitHub and the Invertocat logo are trademarks of GitHub, Inc. Chrome and Chrome Web Store are trademarks of Google LLC. Intel is a trademark of Intel Corporation or its subsidiaries. NVIDIA is a trademark of NVIDIA Corporation.
Don't trust us. Run the verifier.
Five minutes from a clone: build, verify a snapshot, then point it at a vault on testnet.
A live run reads the chain itself: verify --vault. On demo.vaults.probarion.testnet it passes checks a to i.