Octobooks for developers
Run your company on your own code? Octobooks is the books underneath: your cron job posts, issues, reconciles and reads the trial balance, with nobody in a chat. Every plan, trial included. Let us go.
1. Quick start
Three lines, no sign up. The public key opens a sandbox: a shared copy of a demo company, remade every night.
curl https://mcp.octobooks.ai/octobooks/api/v1/company -H "Authorization: Bearer obk_sandbox_demo_foods_public_key_resets_every_night"
curl "https://mcp.octobooks.ai/octobooks/api/v1/statements/trial-balance?date_from=2026-04-01&date_to=2026-10-31" -H "Authorization: Bearer obk_sandbox_demo_foods_public_key_resets_every_night"
curl -X POST https://mcp.octobooks.ai/octobooks/api/v1/tools/manual_journal -H "Authorization: Bearer obk_sandbox_demo_foods_public_key_resets_every_night" -H "Idempotency-Key: first-entry" -H "Content-Type: application/json" \
-d '{"action": "post", "reason": "my first entry", "journal": {"date": "2026-10-01", "narration": "First entry", "lines": [{"account": "7000", "debit": "10.00"}, {"account": "1200", "credit": "10.00"}]}}'
It sends nothing, files nothing and reaches no bank. 30 requests a minute from one address, 2,000 new entries a day for all visitors together.
2. Your own key
- Open Settings, Developers in the app. Name, scopes, Create. The key is shown once; copy it into your machine.
- Read, propose and upload keys take one click. A book key asks for your authenticator code, or your password, or Confirm with Google.
- A key works in one company, under its app name, until you end it. We keep only its hash.
3. What a key may do
read: the books, the statements, the open list, the events.propose: answers, drafts and entries put forward.upload: bank statements and documents.book: post entries, issue invoices and credit notes, release, reconcile, lock periods, as far as your company's own switches let your AI.
A book key has the same switches, the same approval workflow and the same audit trail as your AI, with the key's app name as the actor. Where you decide, it waits for you. Payments and filings stand behind two switches of their own, off until you switch them on.
4. Every tool is an endpoint
POST /tools/<tool> takes the arguments of any tool of the MCP connector as its JSON body. GET /tools lists them with scope and arguments. Besides them stand the typed resources: statements, invoices, bank lines, open items, events. The whole description: openapi.json.
A tool that needs a person in the chat answers 409 with one line that says so.
5. Idempotency
Every POST that writes takes the header Idempotency-Key: a new one per thing you want done. The same key with the same body returns the first answer, with Idempotent-Replay: true. The same key with another body is 409. So a call that timed out can be sent again.
curl -X POST https://mcp.octobooks.ai/octobooks/api/v1/tools/contact_set -H "Authorization: Bearer obk_..." -H "Idempotency-Key: customer-4711" -H "Content-Type: application/json" \
-d '{"what": "save", "side": "customer", "name": "Hill Foods Ltd"}'
6. Rate limits and errors
600 requests a minute per key, 240 tool calls of which 60 write. Over the ceiling: 429 with Retry-After. A body is at most 8 MB.
Errors are {"error": {"code", "message"}}. 401 no key, 403 a scope or a switch, 404 not found in this company, 409 a conflict or a person needed, 422 not acceptable, the message says why.
7. Events and webhooks
Add your https address under Settings, Developers and get a signing secret, shown once. Or read GET /events. Events: journal.posted, invoice.issued, open_item.opened, open_item.resolved, filing.filed. An event holds ids, kinds, dates and amounts, no text an outsider wrote.
Octobooks-Event: journal.posted
Octobooks-Delivery: 1234
Octobooks-Signature: t=1791234567,v1=5f2b...
{"id": "evt_88", "type": "journal.posted", "company": "ltd", "subject": {"type": "journal", "id": 4711}, "data": {"total": "120.00", "currency": "GBP"}}
Check the signature first: v1 is the HMAC-SHA256, in hex, of t, a dot and the body as it arrived. Refuse a t older than five minutes.
def genuine(secret: str, header: str, body: bytes) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
signed = parts["t"].encode() + b"." + body
mine = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(mine, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
Answer any 2xx within ten seconds. Anything else is tried again eight times over about two days.
8. AI clients
Using Claude or another MCP client, with a person in the chat? Connect it with the MCP connector at https://mcp.octobooks.ai: the same tools, the same switches.
Feedback, questions, want a feature? hello@octobooks.ai
Octobooks Ltd, 17549566, London