Books
Package books is double-entry accounting: chart of accounts, ledger, bank reconciliation, and the reports that prove the books balance.
Package books is double-entry accounting: chart of accounts, ledger, bank reconciliation, and the reports that prove the books balance.
| Base URL | https://api.hanzo.ai |
| Operations | 25 |
| Auth | Authorization: Bearer $HANZO_API_KEY |
books
ListAccounts returns the org's chart of accounts — the seeded fixed chart every posting key in the ledger refers to.
GET /v1/books/accounts
ListAccounts returns the org's chart of accounts — the seeded fixed chart every posting key in the ledger refers to.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
AskBooks answers a plain-language question about the caller's own books — "what is my MRR?", "how long is my runway?" — with figures taken from their ledger, never a guessed number.
POST /v1/books/ask
AskBooks answers a plain-language question about the caller's own books — "what is my MRR?", "how long is my runway?" — with figures taken from their ledger, never a guessed number. A deterministic keyword router picks the intent and reads the real metrics, and those figures, followups and report sources are computed BEFORE any model call and are never altered by one: the optional narration seam only rephrases the sentence, and it degrades silently to the templated answer when no AI plane is wired. It is strictly read-only — it restates the books, it never posts to them.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
from | string | — | From is the RFC3339 start of the metric window. |
question | string | — | Question is the plain-language question about the org's books, e.g. "what is my MRR?". |
to | string | — | To is the RFC3339 end of the metric window. |
BalanceSheet returns the org's Balance Sheet as of to (empty = all time), with the Assets == Liabilities + Equity equation proof.
GET /v1/books/balance-sheet
BalanceSheet returns the org's Balance Sheet as of to (empty = all time), with the
Assets == Liabilities + Equity equation proof.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
to | query | string | — | To is the RFC3339 instant the statement is struck as of. |
post_v1_books_bank_exchange
POST /v1/books/bank/exchange
post_v1_books_bank_import
POST /v1/books/bank/import
post_v1_books_bank_link-token
POST /v1/books/bank/link-token
SyncBank pulls every connected bank (Plaid/Teller) for the caller's org, maps each fetched transaction to a posting and books it idempotently, then advances that connector's cursor so the next sync resumes where this one stopped.
POST /v1/books/bank/sync
SyncBank pulls every connected bank (Plaid/Teller) for the caller's org, maps each fetched transaction to a posting and books it idempotently, then advances that connector's cursor so the next sync resumes where this one stopped. One connector's outage is skipped rather than failing the whole sync. It reports the batch: how many transactions were seen, how many vouchers posted, how many inflows reconciled against the processor clearing account, how many raised a question, how many were own-account transfers, and how many were already-processed no-ops. It is READ-ONLY against the bank — it ingests, it never sends money.
ListBankTransactions returns the org's normalized bank transactions, newest first — every row the import and connector paths have ingested, with its amount in exact cents, its direction, and whether it has been matched to a voucher yet.
GET /v1/books/bank/transactions
ListBankTransactions returns the org's normalized bank transactions, newest first — every row the import and connector paths have ingested, with its amount in exact cents, its direction, and whether it has been matched to a voucher yet.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
limit | query | integer | — | Limit caps how many rows come back; 500 when absent or not positive. |
ListUnreconciled returns the org's unmatched bank inflows and their open clarifying questions — the queue a human answers so an unexplained deposit is never guessed into revenue.
GET /v1/books/bank/unreconciled
ListUnreconciled returns the org's unmatched bank inflows and their open clarifying questions — the queue a human answers so an unexplained deposit is never guessed into revenue.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
ExportPackage returns the complete financial package for the caller's org over (from, to]: the trial balance, the P&L, the balance sheet, and the GL detail behind them — the four statements a tax preparer or an investor asks for, assembled from the one ledger in a single read so they cannot disagree with each other.
GET /v1/books/export
ExportPackage returns the complete financial package for the caller's org over (from, to]: the trial balance, the P&L, the balance sheet, and the GL detail behind them — the four statements a tax preparer or an investor asks for, assembled from the one ledger in a single read so they cannot disagree with each other.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
from | query | string | — | From is the RFC3339 start of the window, exclusive. |
to | query | string | — | To is the RFC3339 end of the window, inclusive. |
format | query | string | — | Format is the export encoding. |
limit | query | integer | — | Limit caps the GL detail rows included as the audit trail; 5000 when absent or not positive. |
ListGL returns the org's most recent GL Entry rows, newest first.
GET /v1/books/gl
ListGL returns the org's most recent GL Entry rows, newest first. This is the raw double-entry detail behind every statement: one row per leg, with its debit, credit, posting time and the source that booked it.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
limit | query | integer | — | Limit caps how many rows come back; 500 when absent or not positive. |
ListInbox returns the org's open document queue — everything uploaded but not yet booked, newest first, each with its extracted summary and the confidence the scanner resolved its category at.
GET /v1/books/inbox
ListInbox returns the org's open document queue — everything uploaded but not yet booked, newest first, each with its extracted summary and the confidence the scanner resolved its category at. A booked document drops out of the queue.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
post_v1_books_inbox
POST /v1/books/inbox
Metrics returns the org's deterministic SaaS-metrics snapshot over an optional (from, to] window — MRR, ARR, revenue, COGS, burn, gross margin, net income, cash, deferred revenue, monthly burn and runway — as raw int64-cent figures AND the same figures already formatted.
GET /v1/books/metrics
Metrics returns the org's deterministic SaaS-metrics snapshot over an optional (from, to] window — MRR, ARR, revenue, COGS, burn, gross margin, net income, cash, deferred revenue, monthly burn and runway — as raw int64-cent figures AND the same figures already formatted. Every number is the ledger, aggregated the one way the books define it, never a guess; it is the grounded read the unified /v1/ask advisor replays.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
from | query | string | — | From is the RFC3339 start of the window, exclusive. |
to | query | string | — | To is the RFC3339 end of the window, inclusive. |
ProfitAndLoss returns the org's accrual-basis Profit & Loss over an optional (from, to] window of RFC3339 posting times: recognized revenue, matched cost, and the net.
GET /v1/books/pnl
ProfitAndLoss returns the org's accrual-basis Profit & Loss over an optional (from, to] window of RFC3339 posting times: recognized revenue, matched cost, and the net.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
from | query | string | — | From is the RFC3339 start of the window, exclusive. |
to | query | string | — | To is the RFC3339 end of the window, inclusive. |
ListQuestions returns the clarifying questions the caller's own recent GL raises — the unusual postings a founder should look at (outliers, reversals, round-offs, uncosted revenue, an overdrawn wallet), sharpest first.
GET /v1/books/questions
ListQuestions returns the clarifying questions the caller's own recent GL raises — the unusual postings a founder should look at (outliers, reversals, round-offs, uncosted revenue, an overdrawn wallet), sharpest first. An empty list means the books look clean; the detector is deterministic over the ledger and invents nothing.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
ListRules returns the org's auto-categorization rules, highest priority first.
GET /v1/books/rules
ListRules returns the org's auto-categorization rules, highest priority first. A rule is a standing instruction — "anything whose merchant contains X books to category Y" — and it overrides a vendor's default category, so this is the list that decides how a future bill classifies itself.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
UpsertRule creates or updates one auto-categorization rule, keyed by its pattern — writing a pattern that already exists REPLACES that row's category and priority.
POST /v1/books/rules
UpsertRule creates or updates one auto-categorization rule, keyed by its pattern — writing a pattern that already exists REPLACES that row's category and priority. The category is normalized to a real COA expense account, and anything unrecognized becomes 5900 Uncategorized rather than a guessed real account. It answers the row exactly as stored, so the caller sees the normalization. A rule overrides a vendor's default category, so this is the standing instruction that decides how a future bill classifies.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
category | string | — | Category is the COA expense account a matching bill books to. |
pattern | string | — | Pattern is the merchant substring the rule matches on, case-insensitively. |
priority | integer | — | Priority breaks ties: when several patterns match, the highest wins. |
BookScan posts a reviewed scanned bill to the ledger.
POST /v1/books/scan/book
BookScan posts a reviewed scanned bill to the ledger. It is the scanner's ONLY write: the voucher goes through the same post() choke point every other source uses, so it is checked to balance (Σdebit == Σcredit) and is idempotent by (scan, scanId) — re-booking the same scan answers posted=false and writes nothing. A bill whose economic identity (vendor, total, issue date) already posted under a DIFFERENT scan is refused 409 unless override is set, which is what stops the same receipt re-scanned into a new file hash from double-booking. An unbalanced voucher is refused 400.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
override | boolean | — | Override books this bill even when one of the SAME economic identity (vendor, total, issue date) already posted — the ex |
scanId | string | — | ScanID is the scanned document's file hash, as GET /v1/books/inbox and the scan draft report it. |
voucher | cloud_Voucher | — | Voucher is the reviewed voucher to post. Its source is FORCED to (scan, scanId) server-side, so it can never be booked u |
post_v1_books_scan
POST /v1/books/scan
Sync ingests the caller's OWN org from commerce into BOTH ledgers (live and sandbox) and reports how many new vouchers posted to each.
POST /v1/books/sync
Sync ingests the caller's OWN org from commerce into BOTH ledgers (live and sandbox) and reports how many new vouchers posted to each. It is idempotent — money that has already been booked posts nothing on a repeat — and it is read-only against commerce: it never mints a deposit, a credit or a payout, only the accounting twin of money that already moved.
ListTransactions returns the org's booked ledger as a single-line register, newest first: one row per voucher, with its date, description, vendor, category, source and amount in exact cents.
GET /v1/books/transactions
ListTransactions returns the org's booked ledger as a single-line register, newest first: one row per voucher, with its date, description, vendor, category, source and amount in exact cents. It is the double-entry ledger projected to the register a human reads, filterable by posting-time window, category and vendor. Strictly read-only — it restates the books, it never moves them.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
from | query | string | — | From is the RFC3339 start of the posting-time window, inclusive. |
to | query | string | — | To is the RFC3339 end of the posting-time window, inclusive. |
category | query | string | — | Category filters to one COA account, named by number ("5300") or by category slug ("software"). |
vendor | query | string | — | Vendor filters to rows whose vendor or description contains this text, case-insensitively. |
limit | query | integer | — | Limit caps how many rows come back; 200 when absent or not positive. |
TrialBalance returns the org's trial balance over an optional [from, to] window of RFC3339 posting times, including the opening/closing columns and the TotalDebit == TotalCredit proof that the books balance.
GET /v1/books/trial-balance
TrialBalance returns the org's trial balance over an optional [from, to] window of RFC3339 posting times, including the opening/closing columns and the TotalDebit == TotalCredit proof that the books balance.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true". |
from | query | string | — | From is the RFC3339 start of the window, exclusive. |
to | query | string | — | To is the RFC3339 end of the window, inclusive. |
ListVendors returns the org's vendor book: each canonical vendor, the alias spellings a receipt may print it under, and the expense account new bills from it default to.
GET /v1/books/vendors
ListVendors returns the org's vendor book: each canonical vendor, the alias spellings a receipt may print it under, and the expense account new bills from it default to. A vendor here is what makes a scanned bill self-classify instead of asking again.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
sandbox | query | string | — | Sandbox reads the org's SANDBOX ledger when it is exactly "true"; anything else reads the live one. |
UpsertVendor creates or updates one vendor in the org's vendor book, keyed by its canonical name — writing a canonical name that already exists REPLACES that row's aliases and default category.
POST /v1/books/vendors
UpsertVendor creates or updates one vendor in the org's vendor book, keyed by its canonical name — writing a canonical name that already exists REPLACES that row's aliases and default category. A category given as a slug ("software") is normalized to its real COA expense account, and anything unrecognized becomes 5900 Uncategorized rather than a guessed real account. It answers the row exactly as stored, so the caller sees the normalization. Recording a vendor is what makes future bills from it self-classify instead of asking again.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
aliases | string[] | — | Aliases are the other spellings a receipt may print the vendor under; a scan matching any of them resolves to this vendo |
canonical | string | — | Canonical is the vendor's one true name, and the key an upsert writes by. |
defaultCategory | string | — | DefaultCategory is the COA expense account new bills from this vendor book to. |
How is this guide?