Bursar
[ 01 ]

What Bursar is

An AI treasurer for small companies that pays invoices within limits it cannot change.

Every company pays invoices. Two things go wrong, often: someone pays a fake invoice (the "please note our new bank details" fraud, the most common business scam in the world), and someone pays the same invoice twice. Letting an AI do the work makes both worse, unless the AI never holds the keys.

Bursar splits the job in three. The AI reads the invoice inside a trusted execution environment on NEAR AI Cloud and reports what it says. The contract decides: a NEAR smart contract owned by the company checks the vendor, the payout, the amounts, the orders, and pays or refuses by itself. A dumb executor moves the money, and only to the destination the owner recorded. Nobody in the loop can both decide and move money, and the AI cannot choose an address.

Bursar is software, not a payment service. The USDC stays in the company's own contract, with the company's keys. Nothing passes through Bursar.

[ 02 ]

How a payment flows

  1. An invoice PDF arrives: dropped in the console, posted in a Telegram chat connected to the treasury (it shows up in Inbox, unread, until a person presses Read), or in the inbox folder the agent watches.
  2. The agent rasterizes it and sends the page to a model running in a TEE on NEAR AI Cloud. First it fetches an attestation for a fresh nonce; the answer comes back as structured JSON with an ECDSA signature over the exact bytes.
  3. The agent turns the answer into a claim (vendor, invoice number, amount, payout printed on the invoice, order reference, flags) and calls request_payment on the policy contract. Its only key can call that one method on that one contract.
  4. The contract decides, deterministically and on chain, in the same transaction.
  5. A vendor on NEAR is paid in that transaction. A vendor on Base, Arbitrum, Solana or Sui is queued for the executor, which settles through NEAR Intents to the address on record, verified by the contract before any USDC leaves (mainnet only).
  6. Every decision is an on-chain event and carries a reference to the signed receipt of the reading. There is no database.
[ 03 ]

The rules the contract enforces

The owner sets them; the AI cannot touch them. Each refusal has a reason code you see in the console, the dashboard and the explorer.

unknown_vendorThe vendor must be in the owner's allowlist, by id. payout_changedThe payout printed on the invoice must equal the one the owner recorded for that vendor. A "new bank details" invoice dies here, blocked, not paid. duplicate_invoiceOne invoice number per vendor, ever. over_payment_capNo single payment above the per-payment cap. over_daily_capNo more than the daily cap in one day, across all vendors. over_monthly_budgetNo more than the vendor's monthly budget in one month. insufficient_treasuryNot enough USDC in the contract. over_thresholdAt or above the approval threshold the payment is held for a person: the DAO council votes, or the owner or an approver decides. no_orderNothing the company agreed to buy covers this invoice. Held for a person. flaggedThe reading carries a flag: the model noticed something (urgency, new payment details), or one of the cross-checks on its reading failed (see below). Held for a person. The AI can add scrutiny, never remove it. identity_mismatchThe vendor's tax id printed on the invoice is not the one the owner recorded for that vendor. A name can be imitated; the id cannot. Held for a person. buyer_mismatchThe invoice is not addressed to the company's own tax id: someone else's invoice, by mistake or on purpose. Held for a person. withholding_mismatchThe withholding tax the invoice shows differs from the rate the company's accountant set on this vendor, or the vendor has none set and the invoice shows one. Held for a person.

Reading errors made harmless

The model can misread a number. Five checks that do not trust the model run on every reading, and each failure is a flag the contract holds on: the total must appear in the PDF's text layer; no larger amount may appear in the document (a subtotal taken for the total is caught); subtotal plus tax must equal the total when the invoice shows them; the model's confidence must be at least 0.6; the currency must be USDC. A scan without a text layer is always held. What remains possible is paying less than the invoice says, to the right account, within the orders and caps: the vendor will say so.

Withholding tax, set by your accountant

Bursar knows no tax rules and does not try to. Many countries make the payer keep back part of what it pays certain vendors, typically freelancers, and remit it to the state: ritenuta d'acconto in Italy, TDS in India, retencion in Spain and Latin America, with rates and bases that differ and change. So the rule lives where it belongs: whoever keeps the company's books sets, per vendor, a country and a withholding percentage (0 for companies and most foreign vendors). The contract then pays the vendor the net, keeps the withheld share in the treasury, earmarked, and shows in Analytics what is due. Remitting it is the company's job; afterwards the owner marks it remitted and the counter goes down. An invoice whose own withholding line disagrees with the rate set waits for a person.

Two things to be clear about. The withheld share is the vendor's money, not the company's: on a 1,000 invoice with 20% withholding the vendor receives 800 and the state 200 on the vendor's behalf, which the vendor later deducts from its own taxes; the company's cost is 1,000 either way. And the company still remits and files exactly as it does today, with its accountant: in Italy the F24 by the 16th of the following month, the Certificazione Unica and the 770; in India the TDS deposit by the 7th and the quarterly certificate; in Spain the modelo 111 each quarter. Bursar does not talk to any tax authority and will not; it keeps the amounts right and visible, per vendor and per month, so the filing is a copy, not a reconstruction.

Who is who: tax ids

Every vendor record can carry the identifier the vendor prints on its invoices: a VAT number in Europe, an EIN in the United States, a CNPJ in Brazil, a GSTIN in India, an ABN in Australia, or, for a freelancer with none, a supplier code the company assigns and asks them to print. The company records its own in Settings. Spaces and punctuation do not matter. Both checks are optional and both hold rather than block, so a tax id read wrong never refuses a real invoice.

Only the owner changes a vendor's payout. The executor cannot redirect funds: the contract compares the recipient it reports with the vendor record before releasing USDC. A transfer that fails on the token contract is rolled back in the callback: balance restored, payment marked transfer_failed.

[ 04 ]

Orders and holds

A registered vendor with the right account could still invent invoices under every cap. Bursar pays only what the company agreed to buy.

  • Purchase order: a reference (PO-2026-118), a total, an optional expiry. Invoices that print the reference consume it until it is spent.
  • Standing order: an amount per period (500 USDC every 30 days). One invoice per period, up to the amount.
  • An invoice that no order covers is held, not blocked: a person sees it in Attention and approves or cancels it. By default only vendors that have orders are held to them; set_order_policy true makes every invoice need an order.

A hold is never silent. The Overview shows what waits for a person, and the hold's reasons are written on the payment: over_threshold, no_order, flagged, or a combination.

[ 05 ]

People, roles, DAO

Owner

The NEAR account that owns the contract: your wallet. It sets limits, vendors, orders and the company name, approves held payments, invites and removes collaborators.

Operators

Collaborators get an on-chain role with three permissions: approve, manage vendors, manage orders. An invite creates an account for them with a single key limited to exactly the methods their role allows, records the role in the contract, and gives you a link that carries the key after the hash sign, so it never reaches a server. Whoever opens it is signed in as that account with that role and nothing else. Remove revokes it on chain.

DAO

From Settings the owner creates a Sputnik DAO with the council of their choice. From then on every held payment opens a proposal that the council votes on, in the console or in Trezu on mainnet. A rejected or expired proposal cancels the payment and releases its budget; the contract reads the verdict back from the DAO itself.

[ 06 ]

The reading and its receipt

The invoice is read by a model running in a TEE on NEAR AI Cloud. The invoice never leaves the enclave in clear text. The answer comes with a receipt anyone can verify, without the API key and without trusting the agent:

  • the exact request and response bytes, and their hashes;
  • the enclave's ECDSA signature over model:sha256(request):sha256(response);
  • the attestation report with the Intel TDX quote, bound to the signer and to the fresh nonce the agent chose;
  • the quote checked against Intel's collateral (TCB status).

Change one byte and the signature fails. The contract stores a compact reference to the receipt next to the payment, so a decision can always be traced to exactly the model output it was made on. The console runs the same checks in the browser; bursar verify runs them from the terminal.

Invoices by Telegram

Vendors send invoices the way they already do; nobody at the company uploads anything. In Settings the owner connects a Telegram chat and says who it is for: one vendor, or the whole company. The bot gives a link; the vendor (or a colleague) presses Start once, and from then on every PDF posted in that chat lands in the console's Inbox, under that vendor. A person presses Read: the enclave reads it, the contract decides, and the bot tells that chat, and only that chat, what was decided. Nothing is paid from Telegram. A chat linked to one vendor is also a check the AI cannot talk its way around: an invoice from Acme's chat that names another vendor carries the flag chat_vendor_mismatch, and the contract holds it for a person. Connect as many chats as you like, change what a chat is for, or disconnect it, all from Settings. Bursar keeps only the sender, the file name and the vendor; the PDF stays on Telegram until someone presses Read.

Who holds the NEAR AI Cloud key

Two plans. Bursar reading, used for this hackathon demo: the browser goes through Bursar's relay, a Cloudflare Worker that holds a key paid by the team and forwards the bytes untouched, with daily caps. Own key: a company using Bursar brings its own NEAR AI Cloud key, and the invoice goes from the browser straight to the enclave, never through Bursar.

[ 07 ]

Signing in

No password, no server. Three doors on the sign-in page:

  • NEAR wallet. The wallet tells the console who you are. If your account owns a treasury (the registry lists it, the contract confirms it), you pick it and the wallet adds a key limited to that contract to your browser: it signs vendors, orders, limits and approvals, never a transfer. If your account owns none, the console creates one at this first sign-in: a payer account from the testnet faucet, the policy contract deployed with your wallet as owner, test USDC, three demo vendors and their orders, an agent with one key. Bursar pays for the accounts and the contract storage; you pay nothing.
  • Invite link. A colleague's link signs you in with exactly the role they chose.
  • Keys file. For a treasury created with throwaway keys ("Download the keys"), when there is no wallet at all.

Several treasuries live side by side in the console's switcher. "Switch account" takes you back to the door.

The vault: lose the browser, keep the company

Everything that matters is on the contract and comes back at every sign-in: vendors, limits, payments, roles. What lives only in a browser is secret by nature: the agent key, the Telegram inbox token, the labels. A wallet owner keeps them in the vault: the wallet signs one fixed message (no transaction, no cost), the signature becomes an encryption key, the secrets are encrypted in the browser and stored on the contract with set_vault, owner only. A new browser, after signing in with the same wallet, presses "Unlock with the wallet" and gets them back. Nobody can open the vault without that wallet, Bursar included. The contract never reads it. If the wallet's key changes, the vault stays shut: keep the keys backup file too.

A person in the console can also ask the contract directly: request_payment accepts the agent, the owner and the operators. The decision is the same whoever asks; only the contract decides.

[ 08 ]

The console

A static page: nothing to install, every number read from the contract over RPC, every change signed in the browser.

InboxInvoices received through the Telegram bot, grouped by the vendor each chat is linked to, with sender and file name. Read sends one to the enclave and the contract; Discard drops it. The bot tells the chat each decision, and only that chat. OverviewBalance, spent this month, budgets, what waits for a person, the last decisions. InvoicesDrop a PDF or load a recorded reading; watch the enclave read it, the receipt verify, the contract answer. "Request payment" signs with the agent key. AttentionHeld payments to approve or cancel, council votes when there is a DAO, and what was refused, with the reason. VendorsThe allowlist: id, name, the identifier printed on invoices, country, withholding rate set by the accountant, payout on record, monthly budget, active or not. OrdersPurchase orders and standing orders, what each has consumed, close. AnalyticsSpend by month (with the withheld share), by vendor and the mix of decisions, as charts; every payment grouped by vendor with gross, withheld and net; the withholding kept back for the state with "Mark as remitted"; and the accountant's report: an Excel file with five sheets (Summary, Payments, By vendor, By month, Withholding) or a CSV, built in the browser from the chain. SettingsCompany (name, country, tax id), limits, strict order mode, collaborators and invites, Telegram inbox, governance (create the DAO), keys and reading plan.
[ 09 ]

Explorer and registry

The explorer shows the whole network: how many companies, the USDC their contracts hold, what was paid out today, this month and all time, how many decisions, blocked, waiting for a person, and the last decisions across every company. Nothing private: amounts and decisions are on-chain events. Vendor names and invoice numbers appear only on each company's own dashboard.

It reads a small public contract, the registry, where every treasury lists itself when it is created (the console does it; bursar setup too). Entries are hints, not proof: the explorer and the sign-in page read get_roles on each treasury and drop entries whose owner does not match.

[ 10 ]

Run it yourself

The README is a walkthrough in "do X, see Y" form; the short version:

git clone https://github.com/DCSteve96/Bursar && cd Bursar (cd contracts/policy && cargo test && ./build.sh) cd app && npm install && npm test npx tsx src/cli.ts setup --root you.testnet # accounts, contract, USDC, vendors, orders, DAO set -a; source .env.testnet; set +a npm run relayer & npm run agent -- --once --offline # drop --offline to read with NEAR AI Cloud npm run dev status npm run dev verify 1 # the receipt behind payment 1

The agent sends its claims as meta transactions (NEP-366) through a relayer that only forwards request_payment, so the agent owns no NEAR. An MCP server (bursar mcp) lets any assistant drive it with exactly the agent's powers: submit an invoice, list payments, explain a decision, verify a receipt.

[ 11 ]

Custody and limits

  • Software, not a payment service. You run it on your own accounts with your own keys; nothing passes through Bursar. USDC only.
  • The AI never chooses an address. The executor cannot redirect funds. Only the owner changes a payout, and a changed payout on an invoice is a block.
  • Cross-chain payouts through NEAR Intents are mainnet only; on testnet the Base vendor stops at Queued.
  • The verifier checks the signature, the nonce, the quote's binding and the quote against Intel collateral. It does not yet replay the RTMR3 event log or check GPU evidence; the receipt keeps both.
  • The wallet sign-in adds a function-call key. Creating the DAO and inviting collaborators need NEAR deposits, which the payer account kept from creation funds on testnet.
  • Sample invoices are fictional. Nothing in the demo is a real person or company.
  • Paying vendors in a stablecoin is regulated differently from country to country: in some it is unrestricted, in some it must be reported, in a few it is not allowed for businesses. Bursar does not check this and cannot: the company runs the contract on its own accounts, with its own keys, under its own law. Check your jurisdiction before you fund a treasury.

Where invoices are already structured

More and more countries mandate electronic invoices in a fixed format: SDI and FatturaPA in Italy, Peppol across much of Europe and in Singapore, Australia and New Zealand, Factur-X and ZUGFeRD in France and Germany, Verifactu in Spain, KSeF in Poland, CFDI in Mexico, NF-e in Brazil, DTE in Chile, the GST e-invoice in India, Fatoora in Saudi Arabia, e-Fatura in Turkey. The United States has no mandate; PDFs by email are the norm, with Peppol-style exchange only starting. Where a structured format exists, the vendor, the amount, the tax ids and the payment details come as fields, not as a picture. Bursar's reading step is built for the PDF that still dominates everywhere else; where a structured invoice exists, that step becomes optional: a deterministic parser builds the claim, and the contract decides exactly as it does today. This is the direction after the hackathon, not something the demo does.

[ 12 ]

Glossary

treasuryThe company's policy contract, a NEAR account that holds the USDC and the rules. agentThe process (or the browser) that reads invoices and asks the contract to pay. One key, one method. executorThe process that settles cross-chain payments the contract queued. No AI, no choice of destination. payoutWhere a vendor gets paid: a NEAR account, or a chain and an address. Recorded by the owner, compared on every invoice. holdA payment that waits for a person: over the threshold, outside the orders, or flagged by the model. receiptThe signed, attested record of one reading inside the enclave. TEETrusted execution environment: hardware-isolated compute (Intel TDX here) that proves what ran with an attestation quote. registryThe public list of treasuries the explorer and the sign-in page read.