Telegram-native treasurer for a Binance Agentic sub-account
It asks before it spends.
Every order is confirmed first, kept inside hard caps and written to a hash-chained ledger you can verify yourself.
One order, replayed from the offline demo
- Official Binance MCP server
- OAuth 2.1 with PKCE
- Hash-chained JSON ledger
- Offline demo against a fake exchange
Guide
From /start to a verified receipt.
Bursar lives in one Telegram chat and there is nothing to install beyond Telegram. You pair it once, connect Binance once, then talk to it in plain English or Hinglish and tap the buttons it gives you.
- 01
Open the bot
Send /start. A fresh instance prints a one-time pair code in its server console; /pair with that code binds the desk to your Telegram account, and everyone else is refused from then on.
/start - 02
Connect Binance
/connect answers with one button to Binance's own login page. Bursar receives an OAuth token scoped to the Agentic sub-account. No API key is typed anywhere, and no withdrawal path exists. While Binance admits only its listed agents, the hosted bot runs on the paper desk and /connect says so.
/connect - 03
Ask the desk
Prices and balances by command or in plain words. /price btc and /balance work, and so do "what's btc doing" and "how much do I have". The rule parser needs no language model for any of this.
what's solana at - 04
Place an order
Say the side, the coin and the amount you mean. Bursar walks the live order book for that size and the ticket shows the expected fill, slippage and spread, the 24h range, a thin-book warning when it applies, fee basis, balance after and today's counter. Tap Confirm within 120 seconds or let it expire; either way a ledger line is written.
buy 10 usdt of btc - 05
Leave a standing order
Alerts, conditional buys and schedules, each with a per-order cap, a total cap and a maximum number of runs. Ask mode sends you a ticket when it triggers; auto mode runs inside the caps only if you said "without asking". /orders lists them, /pause and /cancel stop them.
every day at 9am buy 10 usdt of eth - 06
Check the book
/ledger shows the last receipts, /pnl replays them into cost basis and P&L, /brief is the whole desk in one message, every morning if you ask. /verify re-walks the hash chain and names the first broken link, if there is one. /freeze stops everything that moves money until /unfreeze.
/verify
@thebursarbot is bound to its owner, like every Bursar. Open it from any other Telegram account and it answers with a one-line refusal and the repository link. To run your own desk, clone the repository, set a bot token from @BotFather and start it; the README covers the OAuth callback.
Ticket
Everything you need, before you confirm.
The ticket is the same object the bot will execute, not a summary written afterwards. Amount, estimate, fee basis, caps and expiry come from one calculation.
The consequence in one line
Side, pair and amount, in the quote asset you typed. Nothing is inferred silently.
Estimates are marked as estimates
The tilde is the reference price at ticket time. The fill price comes from the exchange and is reported on the receipt.
Caps in view before you decide
Balance after the order and the daily counter sit on the ticket, so you never confirm against a number you have not seen.
Expiry is a hard stop
An unconfirmed ticket dies after 120 seconds. Cancel is the same size as Confirm, and a cancelled ticket writes a ledger line too.
Limits
Hard limits. Not suggestions.
Caps are configuration, not conversation. A request outside them is blocked and logged, and there is no phrasing that gets around a guard.
From the offline demo after two automatic runs. Every run is a ticket, and every ticket is a ledger line.
- 01
Per-order cap
25 USDT
Default, set by the operator in configuration as the ceiling. /limits lowers it at once from chat; a raise waits 24 hours and never passes the ceiling. A 500 USDT request is refused before any ticket is drafted.
- 02
Daily cap
100 USDT
Counted on settled buys, standing orders included. Resets at midnight in the configured timezone.
- 03
Ticket lifetime
120 s
An expired ticket cannot be confirmed. A new message produces a new ticket at the current price.
The counter
Money moves the way it does at a counter.
You state the order. The teller writes a ticket. Nothing leaves the till until you sign, or until a standing instruction you signed earlier comes due inside its caps. Every step is entered in the book.
Ledger
Receipts you can verify, in this tab.
The offline demo's ledger, checked here with the bot's own hash rule. Each entry links to the one before it. Change one number and see exactly where the chain breaks.
| # | Kind | Summary | prev → hash | Check |
|---|---|---|---|---|
This table is filled by your browser from demo-ledger.jsonl. Without JavaScript, download the file and run npm run verify -- ledger.jsonl in the repository. | ||||
Scroll to inspect all entries. hash = SHA-256 of the entry with sorted keys and no whitespace, prev included. The first entry points at 64 zeros.
Rails
Three parties, one path for money.
Telegram is the surface, Bursar is the policy, Binance is the venue. No step is skipped and no party is trusted with more than its role.
Read the code, run the demo.
Node 24, two JSON files, no database, no build step. The whole conversation replays offline against a fake exchange.
View the sourceStatus
What is built, and what is not.
Built for the Binance Agent OS Mini Hackathon, Track A. This is the honest boundary of the build; the status page shows the live values.
What works today?
- Confirm-first tickets with caps, balance-after and 120 second expiry
- Standing orders: alerts, conditional buys and schedules, ask or auto mode, pause, resume and cancel
- Hash-chained ledger with an offline verifier and a tamper test
- Offline demo of the whole conversation against a fake exchange
- OAuth client metadata and callback for the Binance MCP server
What is not built, or not by design?
- Binance's authorization server currently admits only its listed agents (Claude, Codex, ChatGPT, VS Code, Grok); a self-served client id is rejected with error 3346001. The OAuth and MCP code is complete and tested, so the hosted bot and the demo video run on the paper desk: real Binance prices, simulated fills, every receipt labelled Paper order
- Limit orders, derivatives and withdrawals are not built
- Self-hosted: one owner per bot, one sub-account. The hosted bot runs in hosted mode instead, where every Telegram user gets their own paper book and their own ledger; those desks share nothing but the process
- No success rates, no counters, no badges: the ledger is the only proof this project offers
Which account does it trade on?
An Agentic sub-account, authorised through Binance OAuth. Bursar never asks for exchange API keys and never sees the main account.
Which order types are supported?
Spot market orders only, so a ticket always means the same thing. Limit orders and derivatives are not built. There is no withdrawal tool wired in; the capability is absent, not disabled.
Who can operate it?
One Telegram account. The bot is claimed once, with a pairing code printed at start-up or an owner id pinned in configuration. Anyone else gets a refusal, never a ticket.
Do standing orders get the same caps?
Yes. Per-order cap, total cap and a maximum run count per order. Ask-first by default; auto mode only when you say so. Pause, resume or cancel at any time.
What happens when the exchange does not answer?
The budget stays reserved and the order is looked up by its client order id on the next tick. An unknown result is never reported as a failure or a fill.
Does it need a language model?
No. Commands and the fallback parser are deterministic rules. A configured model only widens phrasing coverage, hands back to the rules on doubt, cannot switch a standing order to auto by itself, and never places an order.
Where does state live?
Tickets, standing orders and the ledger are JSON files in a directory you choose. Back them up by copying them. This page is static HTML with fonts served from this domain, no analytics and no third-party requests.
git clone https://github.com/bunnyyxtan/bursar && cd bursar && npm install && npm run demo