Give your agent books.
AI3 Ledger is double-entry accounting for an agent whose work is done by agents. Any agent, on any runtime, keeps them with one key over HTTP or MCP: it reports what it spends, raises and sends invoices, records what is paid, and reads its own runway. It needs nothing else from AI3.
What it is
- Real books. A chart of accounts, journals, periods, invoices in any currency with hosted pages, bills, bank and wallet feeds, reconciliation proposed by a model, profit and loss, a balance sheet that is checked rather than assumed.
- Never estimated. Every figure is posted from a document or a cost record. An amount that is not known is refused, not booked as zero.
- One agent per key. A key reads and writes one agent's books and nothing else. A person's token may act across every agent they own.
- The same tools everywhere. The 35 tools below are the same on the HTTP API, on the MCP, and behind the finance screens. One core, three doors.
From nothing to books
Four calls. The first needs a personal token (or a signed-in browser); the rest use the agent key it returns.
curl -X POST https://ai3.co/api/ledger/v1/organisations \
-H "authorization: Bearer ai3t_YOUR_TOKEN" -H "content-type: application/json" \
-d '{ "name": "Lovelace Analytical", "currency": "USD", "platform": "claude-code" }'
# → { "organisation": { "id", "slug", "companyId", "books" }, "key": "ai3k_…", "scopes": ["read","write"] }
curl -X POST https://ai3.co/api/ledger/v1/costs \
-H "authorization: Bearer ai3k_YOUR_KEY" -H "content-type: application/json" \
-d '{ "costs": [{ "ref": "run-8f2a", "amountMinor": 125, "category": "model", "biller": "anthropic" }] }'
# → { "posted": 1, "duplicates": 0, "transactionIds": ["…"] }
curl -X POST https://ai3.co/api/ledger/v1/tools/create-invoice \
-H "authorization: Bearer ai3k_YOUR_KEY" -H "content-type: application/json" \
-d '{ "customer": "Babbage & Co", "customerEmail": "charles@babbage.example", "lines": [{ "description": "Analysis", "unitAmount": "2500.00" }], "sendTo": "charles@babbage.example" }'
# → issued, given a page at https://ai3.co/i/…, and emailed
curl -X POST https://ai3.co/api/ledger/v1/tools/balance-sheet -H "authorization: Bearer ai3k_YOUR_KEY" -d '{}'
Every tool is POST /api/ledger/v1/tools/<name> with its parameters as JSON, and answers { content, data } or { error }. Amounts you send are in major units with two decimals, as the tools have always taken them; costs are in minor units, because that is what a platform reports. The full contract is openapi.json; the skill an agent can be handed is skill.md.
Report what you spend
POST /api/ledger/v1/costs takes one cost or { costs: [ … ] }, up to 500 at a time. Each one is ref (your own id for it), amountMinor (an integer), and optionally category (model, tool, compute, other), biller, occurredAt, description, and agent, project or work references. Each posts debit the expense account for its category, credit treasury, under the platform your key declares.
A repeated ref is the same transaction, returned again: retry as often as you like. A cost without an amount is refused. This is the same path every agent's run costs and Managed Agents' sessions take; the only difference is who does the reading.
Keys and scopes
| Credential | Speaks for | Scopes |
|---|---|---|
Agent keyai3k_… | One agent's books | read the reports and documents; write documents, costs and reconciliation decisions; admin keys, settings and period close. write implies read; admin implies both. |
Personal tokenai3t_… | A person, across every agent they own or administer | Everything, naming the agent with ?org=<slug> when they own more than one. |
Keys are issued and revoked under Books → Settings → Keys for agents, or with POST /api/ledger/v1/keys and DELETE /api/ledger/v1/keys/<id> (admin). Only a hash is kept; the secret is shown once. A revoked key is refused from the next request.
The tools
Read tools need read; the rest need write. * marks a required parameter; the schemas are in the contract.
| Tool | What it does |
|---|---|
positionread | What the company holds and burns right now: treasury (cash across bank accounts), receivables owed by customers, month-to-date income and expense, trailing 30-day burn, and runway in days. Use this before deciding anything that spends or collects money. |
invoicesread | Invoices the company has raised, newest first, with status, totals, outstanding amount, days overdue, and whether the customer opened the online copy. Filter by status or ask for overdue only.status overdueOnly limit |
invoiceread | One invoice in full: lines, payments received, payment options printed on it, the online link, and sent/opened status.invoice* |
customersread | The customers the company has invoiced or set up, with ids and emails. |
create-invoicewrite | Raise an invoice for a customer. Names a customer (created if new), lists what is being billed, and by default issues it immediately, which posts the receivable and creates the online copy. Pass sendTo to email it in the same step. Amounts are in the invoice currency; a non-base currency is converted at the published rate unless rateToBase is given.customer* customerEmail currency rateToBase lines* dueInDays notes issue sendTo message |
send-invoicewrite | Email an issued invoice to the customer from the company owner’s Gmail, with a link to the online copy. Opens are tracked. Requires the company to be connected to ai3.co.invoice* to cc message |
record-paymentwrite | Record money received against an invoice. Defaults to the full outstanding amount. Books the cash, clears the receivable, and any exchange difference goes to currency gains and losses.invoice* amount date reference rateToBase |
void-invoicewrite | Cancel an invoice that was raised in error. A draft is simply voided; an issued one is reversed so the receivable disappears. Cannot be undone.invoice* reason |
write-off-invoicewrite | Give up on collecting what is outstanding on an invoice: the receivable moves to bad debt expense.invoice* reason |
creditsread | The company’s prepaid model credits at ai3.co: balance left, what was put in, what model usage has been charged (at cost plus the platform markup), and how to top up (pathUSD to the platform wallet with the credit memo, which the pay-invoice tool can send). Pass sync true to book the latest grants and usage into the ledger now.sync |
bank-accountsread | The company’s bank accounts and wallets with the balance in the books, the last statement balance, and how many statement lines still need reconciling. |
reconcile-queueread | Statement lines not yet explained in the books, each with the ledger’s proposal (match an existing transaction, create a new one against an account, a transfer between accounts, or a question with options) and its confidence and reason. Work through these with the reconcile tool.bankAccountId limit |
reconcilewrite | Settle one statement line. Either accept the proposal as shown in the queue, or give a decision: match (transactionIds), create (accountCode, description, contactName), transfer (otherBankAccountId), or exclude (reason). A confirmed decision teaches a rule for the same payee next time.lineId* accept decision |
reconcile-allwrite | Run the matcher over every unreconciled line and post every proposal at or above the confidence threshold (default 90). Returns what was posted and what still needs a decision.bankAccountId threshold |
profit-and-lossread | Income and expense by account for a period. Defaults to the current month to date. Optionally grouped by agent or project.from to groupBy |
balance-sheetread | Assets, liabilities and equity as of a date (default today).asOf |
walletwrite | The company’s stablecoin wallet on Tempo (Stripe’s payments chain, testnet): address, pathUSD balance, explorer link. It is printed on invoices as a payment option and its feed reconciles itself. Pass topUp true to ask the testnet faucet for more test money.topUp sync |
pay-invoicewrite | Pay an invoice the company received. Two rails: pathUSD from the company wallet on Tempo (invoice number in the transfer memo, so the seller’s books reconcile it), or the card the owner saved on ai3.co through Stripe (the seller must take card payments; the charge lands on their Stripe account with the invoice number). Give the invoice’s online link (an ai3.co/i/… URL) and amount, currency, payee and invoice number are read from it; or give a raw wallet address and amount. rail defaults to auto: the wallet when the invoice offers one and the balance covers it, else the card. Books the payment as an expense. An agent pays only inside a spending authority the owner granted on ai3.co: the tool asks first, and a refusal says which rule and where the owner can change it (the authorities page, or the feed while the inspection window is open). Never work around a refusal.invoiceUrl rail to amount memo description accountCode |
striperead | The company’s Stripe through ai3.co: whether card payments are on (invoices then carry a Pay by card button and other companies can pay from their saved card), the card this company has on file for paying others, and links to fix either. Pass connect true to start or continue Stripe onboarding (returns a link the owner opens); sync true to read new Stripe charges, fees and payouts into the books now.connect sync |
dispute-invoicewrite | File a dispute at Recourse (recourse.so), the venue every invoice names, signed with the company wallet. As the buyer, give the invoice’s online link and what went wrong. As the seller, give your own invoice number (for example non-payment) and the buyer’s wallet address. The ruling comes back in about a minute with a fault split and a money instruction on the Tempo rail; use settle-dispute to carry it out.invoiceUrl invoice counterpartyAddress breach remedy evidence verdict amount |
disputeread | Disputes this company is party to, with the ruling and money instruction once decided. Pass a dispute or case id for one and it is refreshed from the venue.dispute |
settle-disputewrite | Carry out a ruling’s money instruction from the company wallet: every transfer the ruling says this company owes is sent in pathUSD with the case id in the memo, and booked.dispute* |
chart-of-accountsread | Every account in the books with its code, name, type and current balance. Use the codes when posting a journal or choosing where a bill line goes. |
post-journalwrite | Post a balanced manual journal: at least two lines, each a debit or a credit to an account code, debits equal to credits. Use it for accruals, corrections, prepayments and anything no other tool covers. Pass draft: true to leave it unposted for a person to review.date narration lines* draft |
journalsread | Manual journals, newest first, with status (draft, posted, voided), date, narration and totals.status limit |
void-journalwrite | Reverse a posted journal so it drops out of every report. The journal and its reversal both stay in the books. Cannot be undone.journal* reason |
trial-balanceread | Every account with a balance at a date, debit balances in one column and credit balances in the other, and whether the two agree. Pass from to see only the movements in a window.asOf from |
entriesread | The posted entries behind a report figure: filter by account code or account type, a date window, an agent, and the kind of source (cost_sweep, invoice, payment, bill, journal, funding, reversal, conversion). Each row names the transaction it belongs to; pass that id to `transaction` for the full story.account type from to agent sourceKind limit |
transactionread | One transaction in full: every debit and credit, what caused it (an invoice, a bill and its attached documents, a bank line, a journal, or the cost event with its agent and run), and whether it was reversed.transactionId* |
suppliersread | Suppliers the company has bills from, with ids, emails and the expense account their bills default to. |
billsread | Bills received from suppliers, newest first, with status (draft, approved, part_paid, paid, void), totals, what is still owed and days overdue.status overdueOnly limit |
billread | One bill in full: lines with their expense accounts, tax, payments made, and the supplier.bill* |
create-billwrite | Record a bill the company owes a supplier. Names the supplier (created if new), lists the lines with the expense account each belongs to, and by default approves it, which books the expense and the payable. Amounts are in the bill currency.supplier* supplierEmail reference date dueInDays currency rateToBase lines* notes approve |
pay-billwrite | Record that a bill was paid, in full by default, from Treasury or a named bank account code. Posts debit Payables / credit the cash account.bill* amount date reference fromAccount |
void-billwrite | Cancel a bill recorded in error. A draft is voided; an approved bill with nothing paid is reversed. Cannot be undone.bill* reason |
From Claude or ChatGPT
AI3 is an MCP server at https://ai3.co/mcp. With a personal token, the same tools appear as ledger_position, ledger_create_invoice and so on, plus open_books (open an agent for its books alone), report_costs and issue_ledger_key. Every write needs confirm: true; called without it, the tool says what it would do.
Rules
- Every transaction sums to zero, and the database refuses one that does not.
- The books are append-only. A correction is a reversal (
void-invoice,void-journal,void-bill), never an edit. - A draft an agent raises changes no report until it is issued.
create-invoiceissues by default;draft: trueleaves it for a person. - A closed period refuses new entries dated inside it.
- Money is integer minor units. Floats are refused at the door.
- Nothing is estimated. A figure is actual, incomplete or unavailable, and says which.