> ## Documentation Index
> Fetch the complete documentation index at: https://zenofirm.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# The tool surface

> Every tool an AI client can call against your firm's QuickBooks Online companies, and the rules all of them follow.

The hosted workspace exposes one tool surface over MCP at
`https://api.zenofirm.com/mcp` — the same surface the console uses.
[Connect an AI client](/docs/cloud/clients) once, and everything below is
available to it, scoped to your firm and to the companies your firm has
connected.

There are 111 of them, in the groups below.

## The rules every tool follows

* **One shape for every answer.** A tool returns its result, or it returns a
  refusal with a plain-language reason and a hint naming what to do instead.
  A tool never guesses its way past a problem.
* **Reads never pause.** Reading your books, your context, your work log and
  your history stays available even when a subscription lapses. Only writes
  pause. Nobody loses sight of data their own ledger contains.
* **Planning writes nothing.** `qb_plan_batch`, `qb_plan_feed`,
  `qb_plan_cleanup`, `qb_import_iif` and `qb_import_table` all resolve, check
  and render. None of them touches QuickBooks.
* **Approval relays a human.** `qb_approve_plan` records words a person
  actually said, under that person's name; a verdict with no words, or
  one the agent tries to record as its own, is refused and nothing is
  saved. A clean plan is not an approval. An approval given in the
  console reaches the conversation through `qb_await_verdict`, which holds
  until the verdict is recorded, so nobody has to go back and say "now post it".
* **Apply refuses drift.** If the plan or the exclusions changed after the
  verdict, applying is refused and a new plan is required.
* **The ledger stays authoritative.** Read models are labeled copies for
  search and speed; every write goes through QuickBooks, never around it.
* **The immediate ones ask twice.** The few tools that act on one document
  without a plan — voiding, deleting, editing in place, changing company-wide
  preferences, emailing a customer — require an explicit `confirm: true`
  rather than acting on a first mention.

## Companies and connection

| Tool                  | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_list_companies`   | The firm's client companies and the state of each connection.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `qb_status`           | Connection health, read-model freshness, and the plans still waiting for a decision.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `qb_company_info`     | Live company profile from QuickBooks — name, country, fiscal year start, address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `qb_sync_mirror`      | Refresh the read models: a full sync the first time, change-data-capture after. Pass `rebuild: true` when the copy is *wrong* rather than merely stale — after a company reset, a restored backup, or a bulk delete done outside Zeno. The transaction window reaches 24 months back by default; pass `historyFrom` (a date, such as the year the file was opened) or `historyMonths` to reach further. The window is per company, is kept by every later sync, and only ever widens. Every full pull also asks how many transactions the company holds dated *before* the window and the earliest of them, and says so — so a window that begins after the file's first transaction is never silent about it. |
| `qb_get_entitlements` | The QuickBooks subscription tier and feature grants behind classes, locations, purchase orders, and budgets.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |

## Reading the books

Most reads answer from the read models, which is why they are fast and why
they carry a sync time. Reads marked *live* go to QuickBooks every call.

| Tool                     | What it does                                                                                                                                                                                                                                       |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_list_accounts`       | The chart of accounts: name, type, balance, active.                                                                                                                                                                                                |
| `qb_find_customers`      | Search customers by name fragment.                                                                                                                                                                                                                 |
| `qb_find_vendors`        | Search vendors by name fragment.                                                                                                                                                                                                                   |
| `qb_list_items`          | Products and services.                                                                                                                                                                                                                             |
| `qb_find_transactions`   | Find transactions by kind, counterparty, document number, amount, or date range.                                                                                                                                                                   |
| `qb_query`               | Read-only SQL over the read models — the cross-cutting question no single endpoint answers. One `SELECT` at a time, always scoped to one company. `format: "csv"` answers with one spreadsheet string in place of rows, ready for a working paper. |
| `qb_list_employees`      | Employees, *live*, inactive included, with the ids a `qb_plan_names` line takes. Deactivating an employee through a plan doubles as termination — a release date records when.                                                                     |
| `qb_list_currencies`     | Currencies enabled for the company, *live*.                                                                                                                                                                                                        |
| `qb_list_tax_codes`      | Tax codes with their rates, *live*. Rates are immutable in QuickBooks — what you see is what transactions get.                                                                                                                                     |
| `qb_list_budgets`        | Budgets, *live*. Read-only in the QuickBooks API: budgets are authored in the QuickBooks interface.                                                                                                                                                |
| `qb_list_customer_types` | Customer types, *live*. Read-only for the same reason.                                                                                                                                                                                             |
| `qb_report`              | Run a QuickBooks report live — Profit and Loss, Balance Sheet, Trial Balance, General Ledger, aged receivables and payables, cash flow, and the rest. Report parameters pass straight through.                                                     |

## The batch loop

Everything that changes the ledger goes through these, in this order. The
loop is described in full under [plan, review, apply,
reverse](/docs/cloud/governed-work).

| Tool               | What it does                                                                                                                                                                                                                                                                                                      |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_plan_batch`    | Preflight a batch into a reviewable plan: resolve names against the ledger, apply the client's coding rules, validate shapes and dates, flag duplicates and already-posted entries. Writes nothing.                                                                                                               |
| `qb_review_batch`  | Re-render a stored plan's approval table and its verdict state.                                                                                                                                                                                                                                                   |
| `qb_await_verdict` | Wait for the human's verdict on a plan, so an approval recorded in the console reaches the conversation with the person's words.                                                                                                                                                                                  |
| `qb_exclude_line`  | Record a reviewer's decision on one line — exclude it, or put it back.                                                                                                                                                                                                                                            |
| `qb_approve_plan`  | Record a human's approval in their own words, pinned to the exact plan and exclusions that were read. Refused without the words or a person's name.                                                                                                                                                               |
| `qb_reject_plan`   | Record a human's rejection, in their words. A refusal is a decision and leaves a trace. The latest verdict counts, so this is also how an approval that has not posted is withdrawn - a plan superseded by a re-plan, or one no longer wanted. Only an applied plan is refused; `qb_reverse_run` undoes that one. |
| `qb_apply_batch`   | Post an approved plan. Refuses without an approval, on drift, or if it was already applied — except a plan whose run was interrupted by a server restart, which `resume: true` continues, skipping by name every line that run posted.                                                                            |
| `qb_list_plans`    | Plans for the firm, newest first, with each one's latest verdict and stage; says how many there are, takes `limit`, and `open: true` keeps only the plans still waiting on someone.                                                                                                                               |
| `qb_list_runs`     | Runs — applies and reversals — newest first.                                                                                                                                                                                                                                                                      |
| `qb_run_detail`    | One run's journalled entries: what posted (with the amount QuickBooks Online posted beside what the plan said, where they differ), what was skipped and why, what failed, what has been reversed.                                                                                                                 |
| `qb_reverse_run`   | Undo a run. Entries reverse in descending order, voided where QuickBooks voids and deleted where it cannot; names the run created are retired last.                                                                                                                                                               |

## The queue

The queue that turns arriving transactions into coded postings. Statements and
live bank connections fill the same queue, and nothing downstream can tell the
two apart — which is why a firm can start on downloaded files and add a
connection later without re-learning anything. These tools are the only road
for coding a line: the console's Bank feeds page shows the result and takes the
verdicts. Working the queue is described in full under
[the queue](/docs/cloud/bank-feeds).

| Tool                   | What it does                                                                                                                                                                                                                                                                                                                                                                           |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_preview_statement` | Read a statement *without* staging any of it: the header as written, which column each role ended up reading, the first rows as the importer would produce them, and what it would skip. CSV column detection is a guess about somebody else's spreadsheet, and this is where a wrong guess gets corrected.                                                                            |
| `qb_import_statement`  | Stage a CSV or OFX/QFX/QBO statement onto the feed. Rows are parsed, deduplicated, and run through the company's coding rules — auto rules fill, suggest rules propose. Writes nothing to QuickBooks.                                                                                                                                                                                  |
| `qb_bank_feed`         | The staged queue with its coding, rule provenance, and suggestions. `view` narrows it to the question actually being asked — needs coding, suggested, ready, matched.                                                                                                                                                                                                                  |
| `qb_code_feed_lines`   | Code, exclude, restore, or match staged lines. A manual edit clears the line's rule provenance, because the badge means "a rule did this". Posted lines refuse edits — reverse the run instead. The batch lands whole or not at all: after a failure nothing changed and the same updates can be sent again; a line that was already matched says so, with the transaction it went to. |
| `qb_match_feed`        | Find what the feed does *not* need to post: ledger candidates already in QuickBooks within \$0.02 and ±5 business days, and mirrored pairs across two fed accounts that are one transfer rather than a check plus a deposit.                                                                                                                                                           |
| `qb_match_options`     | Everything that could stand in for **one** line: the automatic candidates, *groups* of ledger rows that together sum to it (four cheques entered by hand, one lodgement on the statement), the transfer partner, and a free search of the register for the cheque that cleared three weeks late.                                                                                       |
| `qb_plan_feed`         | Build a reviewable plan from pending lines. Money out becomes Checks or card charges, money in becomes Deposits or card credits, and mirrored pairs fold into one Transfer. Each entry carries `bankfeed:<id>`, so the posting stays linked to the raw bank line.                                                                                                                      |

<Note>
  `qb_plan_feed` produces an ordinary plan. It is approved with
  `qb_approve_plan` and applied with `qb_apply_batch` like every other batch — a
  feed that posted its own entries would be a second path to the ledger, and a
  second path is a path where the gates are not.
</Note>

## Live bank connections

Optional, and the only part of the workspace that reaches a third party for
transaction data. Setting one up is a settings job, not a daily one.

| Tool                          | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_connect_bank`             | Start connecting a bank login. Returns a URL for a person to open in any browser — the credentials go to the bank, never through Zeno. `syncFromDate` is where the feed starts: it sets how much history the bank is asked for, up to two years, and skips anything before it. The bank settles that reach once, when the login is connected, so ask for everything the books will ever need. Without a date the bank shares its last ninety days. Pass a `connectionId` instead to re-authenticate a lapsed login, which keeps the cursor and the history. |
| `qb_complete_bank_connection` | Finish a hosted-link session and list the accounts it discovered. Each one stays disabled until it is mapped: discovery is not a decision.                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `qb_map_feed_account`         | Say which QuickBooks bank or credit-card account a discovered account's lines land in, and enable it. Until an account is mapped, its transactions are not staged and the login is not read at all; mapping it brings in its history from the feed's start.                                                                                                                                                                                                                                                                                                 |
| `qb_set_feed_account`         | Turn a mapped account's staging on or off. Disabling pauses a feed without forgetting where it posts or discarding what it already staged; enabling again fills the pause in. A pause is "not now" — `qb_set_feed_start` is how to skip a stretch for good.                                                                                                                                                                                                                                                                                                 |
| `qb_set_feed_start`           | Move where a connection's feed starts. Earlier re-reads the login's history on the next sync — lines already on the feed are recognised by their bank id, not doubled — and reaches back at most to what the bank shared at connect time. Later only narrows what future syncs keep.                                                                                                                                                                                                                                                                        |
| `qb_bank_connections`         | The company's connections and their health. `needsReconnect` is a feed that has **stopped** — a lapsed login fails silently, so treat the flag as work.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `qb_bank_balance`             | The bank's own balance beside the QuickBooks balance for each fed account, with the difference decomposed: feed lines not yet posted (and how many sit in a plan awaiting approval), lines excluded on purpose, and what remains that the feed cannot see. The bank figure is the current balance the bank reported on the last sync, labelled with its as-of; the QuickBooks figure is read live. A gap is a to-do list, not a fault.                                                                                                                      |
| `qb_sync_bank_feed`           | Pull new transactions onto the feed. The server also does this on a schedule.                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `qb_disconnect_bank`          | Disconnect a login. Staged and posted lines keep their history: disconnecting stops the future, never rewrites the past.                                                                                                                                                                                                                                                                                                                                                                                                                                    |

## Expense claims

Turn a fed card account into a claim account and every charge on it grows a
second lifecycle: draft, submitted by the cardholder, approved or sent back by
a reviewer. Only an approved claim can reach a plan. See
[expense claims](/docs/cloud/expenses).

| Tool                       | What it does                                                                                                                                                                                                   |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_setup_expense_account` | Turn claim handling on for a fed account (or off), and record the cardholders who carry its cards. Existing pending lines are backfilled.                                                                      |
| `qb_cardholders`           | Who carries which company card. Read-only.                                                                                                                                                                     |
| `qb_expense_claims`        | The claim queue with each line's claim state, receipt, cardholder, and conversation. `submitted` is the reviewer's court; `draft` and `sent_back` are the cardholder's.                                        |
| `qb_submit_expenses`       | The cardholder's act: submit draft or sent-back claims. Each line needs a linked receipt, an explicit no-receipt reason, or at least a coded account first.                                                    |
| `qb_approve_expenses`      | The reviewer's act, recorded with who and when. Requires a coded account on every line — a claim without a category is a question, not an approval.                                                            |
| `qb_return_expenses`       | The reviewer's other act: send claims back with a required reason, which lands both as the sent-back reason and as a question in the conversation.                                                             |
| `qb_expense_comment`       | Add to a claim's conversation. Comments never change a claim's state — answering a question does not resubmit it.                                                                                              |
| `qb_expense_dashboard`     | Receipt coverage and card spend: month to date against the same days last month, charges missing receipts and how many are over 30 days stale, the breakdown by cardholder and by account, and the work queue. |

<Warning>
  Approving a **claim** clears it for planning. It does not post anything. The
  plan `qb_plan_feed` builds from those lines still needs its own human approval
  before `qb_apply_batch` touches QuickBooks.
</Warning>

## Receipts

| Tool                | What it does                                                                                                                                                                                                                                     |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `qb_match_receipts` | Score inbox receipts against unlinked charges. Amount is required and a receipt more than 10% off is no candidate; dates tolerate settlement lag; merchant matching sees through processor prefixes (`SQ *`, `TST*`, `PAYPAL *`). Proposes only. |
| `qb_link_receipt`   | Link a receipt to its charge, record that a charge needs none, or undo a link. First link holds — re-linking means unlinking first, so a mistake is undone deliberately rather than silently replaced.                                           |

The linked document is the claim's evidence: it rides into submission, it
stops the coverage report counting the charge, and after posting it is what
`qb_attach_document` puts on the QuickBooks transaction.

## Importing a file

The division of labour that makes a large import cheap and safe: the agent
works out the **shape** from fifteen rows, and the engine applies it to every
row deterministically. Reading fifty thousand rows through a model burns the
customer's tokens to produce a plausible-but-wrong ledger. See
[importing and migrating](/docs/cloud/imports).

| Tool                | What it does                                                                                                                                                                                                                                                                            |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_inspect_import` | Look at a file *before* reading it: what format it is, and for a spreadsheet or CSV its headers, a small sample of rows, and which columns parse as dates and amounts.                                                                                                                  |
| `qb_import_table`   | Read a spreadsheet or CSV into a reviewable plan using a column map worked out from that sample. Pass `groupBy` when several rows make one document — a bill register keyed by bill number. The map itself is shown to the reviewer, so a wrong column is caught before anything posts. |
| `qb_import_iif`     | Read a QuickBooks IIF file into a reviewable plan. Name lists become the plan's lists section and transactions become its entries, so one approval covers a whole migration.                                                                                                            |

<Note>
  `qb_import_iif` returns warnings that matter: every block that did not
  reconcile against its own total, every transaction kind QuickBooks Online has
  no equivalent for, and every payment that will post unapplied. Read them
  before approving, not after.
</Note>

## Correcting what is already posted

| Tool                    | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_plan_cleanup`       | Preflight a **bulk** cleanup into a reviewable plan: void, delete or correct many documents already in QuickBooks as one approval table and one reversible run — any number of targets, in as many plans as a reviewer can read. Name them by `select` (kinds, a date range, a name, a line account: everything matching becomes a line, already in dependency order, capped per plan) or by explicit `targets`. A selection carries one action for every match: `Delete` pages, and the same selection again after the plan applies takes the next batch; `Modify` carries one header `patch` (dates, numbers, memos, and the header's location, class, customer or vendor by name) and/or one `recode` rule (lines on account, class, item or customer *A* move to *B*, by name, turned into each document's lines at apply; `paidFrom` moves the bank or card account a purchase was paid from, or the account a deposit went into); `Void` is allowed when everything matching fits in one plan, because a voided document would match the selection again. See [Bulk operations](/docs/cloud/bulk-operations). A target the read models have not seen is read live from QuickBooks rather than refused, so any id `qb_delete_transaction` would accept is accepted here. Each target is pinned to the revision it carries now, so a document somebody edited between approval and apply is refused rather than acted on. Lines act in order, and the plan warns by name when a document is numbered ahead of a payment applied to it. |
| `qb_modify_transaction` | Change one transaction in place. The update is sparse, with one exception: passing `lines` replaces every line, because QuickBooks has no partial line patch. Requires `confirm: true`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `qb_void_transaction`   | Void one transaction: it stays in the ledger at zero, keeping its number and its place in the audit trail. Requires `confirm: true`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `qb_delete_transaction` | Permanently delete one transaction. No stub, no undo. Requires `confirm: true`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |

QuickBooks voids invoices, sales receipts, payments, bill payments and
check-type purchases only. Everything else is refused by name with delete as
the named alternative, rather than letting QuickBooks answer *Unsupported
Operation*. Prefer voiding wherever it is allowed.

For a single document those three are the right tools; a batch of one makes an
approval table lie about what it is. For duplicate bills, a bad import, a
wrong-month batch, a mass recode (a `select` with a `recode` rule) or emptying a file, `qb_plan_cleanup` journals
every document's pre-image before anything happens, so `qb_reverse_run` puts it
back — restoring a void or an edit onto the same document, and re-creating a
deleted one under a new id, saying which it did.

Emptying an old file is the largest case, and it is still this loop: widen the
window with `qb_sync_mirror` (`historyFrom` the year the file was opened), then
`qb_plan_cleanup` with a `select` — every kind, or one at a time — which plans
the batch in dependency order (deposits, then the payments they hold, then the
invoices and bills those pay, then the rest), five hundred documents a plan.
Approve, apply, run the same selection again for the next batch. Keep
customers and vendors active until their documents are gone. There is no
bulk-delete app to add; the plan is the bulk tool, with an approval table and
one reversible run per batch.

## Names and lists

QuickBooks Online has no delete for list names. Deactivation is the only undo,
and it is not destructive: the row leaves every picker, every posted
transaction keeps it, and it can be brought back. Names are created, changed
and retired through a plan a person approves, like everything else that
touches the ledger.

| Tool                   | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_plan_names`        | Create, change or retire accounts, customers, vendors, employees, products and services, classes, locations, terms, payment methods, tax agencies and currencies — as a plan. A tax agency is created once and never changed or retired (QuickBooks Online has no way to); a currency is checked against a live read of the company's list and a switched-off one is turned back on rather than doubled. One approval table, one run, and every change keeps the row's previous state so `qb_reverse_run` puts it back. There is no direct tool for these lists: a name write is a ledger write. Reserved accounts and QuickBooks' shipped terms map to the existing row instead of being duplicated. An employee's SSN and date of birth are refused; a vendor's tax id is stored masked and held only until the run sends it ([what a plan carries but does not keep](/docs/cloud/governed-work#what-a-plan-carries-but-does-not-keep)). |
| `qb_create_names`      | Fix a plan's missing names in one reviewed step: collect every name the batch needs, preview what would be created, then re-plan with those names in the plan's lists section — one approval for the names and the postings that need them.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `qb_create_currency`   | Enable a foreign currency. Refused when multi-currency is off.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `qb_set_exchange_rate` | Pin an exchange rate for a date. Setting it again overwrites that day rather than duplicating it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `qb_create_tax_agency` | Add the tax agency a rate must reference.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `qb_create_tax_code`   | Add a tax code and its rates in one call. Rates are immutable afterwards. Refused on US automated sales tax, which computes tax itself.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `qb_merge_duplicates`  | Handle a duplicate honestly: record an alias so every future plan resolves the old spelling to the survivor, and stage a one-line plan that retires the loser once a person approves it. Posted history stays where it is; a true merge is a QuickBooks interface operation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `qb_map_name`          | Record that alias directly — "the spelling on these documents means this ledger row."                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

<Note>
  QuickBooks refuses some of these itself: a vendor with open transactions
  cannot be deactivated, a bundle cannot be created through the API, and one
  name index is shared across customers, vendors, and employees, so a display
  name can only be used once. Each tool says so rather than failing obscurely.
</Note>

## Company settings

| Tool                     | What it does                                                                                                                                             |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_preferences`         | Live preferences: sales tax posture, class and location tracking, multi-currency, custom fields — the gates that decide what this company's API accepts. |
| `qb_set_preferences`     | Change those company-wide settings. Requires explicit confirmation: two of these flags quietly discard data.                                             |
| `qb_update_company_info` | Update the company's outward-facing identity — the name, addresses, phone, and email customers see on every invoice. Requires explicit confirmation.     |

## Recurring templates

| Tool                  | What it does                                                                                                        |
| --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `qb_list_recurring`   | Recurring transaction templates defined in QuickBooks.                                                              |
| `qb_create_recurring` | Create a template plus the schedule that generates it, reminds someone, or holds it for manual use.                 |
| `qb_delete_recurring` | Delete a template permanently. QuickBooks has no template update, so delete-and-recreate is also how one is edited. |

## Sending and attachments

| Tool                   | What it does                                                                                                                                                                                                                |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_send_invoice`      | Email an invoice or estimate to the customer through QuickBooks. A real email leaves, so it requires confirmation and should follow an explicit instruction.                                                                |
| `qb_get_pdf`           | Fetch QuickBooks' rendered PDF of a transaction.                                                                                                                                                                            |
| `qb_attach_document`   | Upload a file as a QuickBooks attachment, optionally linked to a transaction — the source document riding with the posting.                                                                                                 |
| `qb_attach_documents`  | Upload many files as attachments in **one run** — a folder of receipts, each riding with its transaction. Every upload is a line on the run, and `qb_reverse_run` deletes the attachments the run made. Up to 100 per call. |
| `qb_list_attachments`  | List attachments, optionally those linked to one transaction.                                                                                                                                                               |
| `qb_delete_attachment` | Permanently delete an attachment and every link it has. Deleting a transaction does *not* delete its attachment, which is why this exists. Requires `confirm: true`.                                                        |

## The firm inbox

| Tool                  | What it does                                                                                                                                                |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_inbox`            | Documents waiting in the firm's inbox, newest first.                                                                                                        |
| `qb_get_document`     | Read one document — images and PDF pages come back to look at, text files as text.                                                                          |
| `qb_update_document`  | Say whose books a document belongs to and what kind of evidence it is.                                                                                      |
| `qb_resolve_document` | Close a document out of the inbox, either against the plan that carries its work — the audit path from a posting back to its evidence — or as needing none. |

## Scheduled work

A recurring engagement can carry a playbook, and an agent on your own machine
can work it on its cadence. Zeno cannot start that agent — it calls in — so
the machine keeps a daily heartbeat and Zeno keeps the calendar. Binding a
playbook and letting it run unattended are separate decisions, and a run still
stops at a plan for a person to approve.

| Tool                       | What it does                                                                                                                                                                                                                                                                                 |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_list_engagements`      | The firm's recurring work: what runs for each client, how often, which playbook it is bound to, and whether an agent may run it. Also lists the machines that have checked in and when each was last heard from.                                                                             |
| `qb_bind_playbook`         | Attach a playbook to a recurring engagement so an agent can run it on that cadence, or detach one. Arguments may be literals or period expressions the runner resolves. Binding is not permission: an engagement can be bound and still withheld from agents.                                |
| `qb_create_engagement`     | Set up recurring work for a client: a standing job that opens a period every cycle, is due a set number of days after the period ends, and sits on Today until a person closes it. Optionally binds a confirmed playbook in the same call. Refuses an unknown timezone and a draft playbook. |
| `qb_retire_engagement`     | End a recurring engagement. No new periods open; a period still open stays on Today until it is closed.                                                                                                                                                                                      |
| `qb_close_period`          | A person's verdict on one period: done, skipped, or open again. Never called inside a scheduled run — a period is done when the work is approved, not when an agent prepared it.                                                                                                             |
| `qb_park_period`           | Take one open period off Today until a date, or put it back. Parking does not close it or change when it was due.                                                                                                                                                                            |
| `qb_due_work`              | What recurring work is due right now, across every client — the first call of a scheduled session. Each item carries its playbook and resolved arguments. Also the heartbeat: it records that this machine is awake, including on a wake with nothing due.                                   |
| `qb_start_scheduled_work`  | Claim one due period and get the procedure to follow, with arguments substituted and the client knowledge it needs. The claim is a lease, so two machines cannot work the same period.                                                                                                       |
| `qb_finish_scheduled_work` | Record what a run did and release the claim: `prepared` with the plan ids it produced, `nothing_to_do`, or `blocked` with the reason. Never closes the period — the work is not finished until a person approves what was prepared.                                                          |

## Firm memory

Rules apply themselves. Knowledge and playbooks wait for a person to confirm
them, and editing one returns it to draft.

| Tool                   | What it does                                                                                                                                                                                                                                                                                                                                                 |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `qb_suggest_coding`    | Triage descriptors before building a batch: for each one, the saved rule that matches it, or — when none does — what the ledger's own history says this counterparty gets coded to, with the supporting line count and most recent date. The ones that come back unresolved are the lines that actually need a decision.                                     |
| `qb_test_rule`         | Dry-run a rule against the pending feed *before* learning it. "This catches these 14 lines" beats "trust me". Nothing is saved.                                                                                                                                                                                                                              |
| `qb_learn_rule`        | Save a coding rule: this descriptor means that account. Rules only ever fill fields that were left empty.                                                                                                                                                                                                                                                    |
| `qb_list_rules`        | The company's rules in priority order, with usage counts.                                                                                                                                                                                                                                                                                                    |
| `qb_forget_rule`       | Retire a rule. Its history of use stays on the record.                                                                                                                                                                                                                                                                                                       |
| `qb_write_knowledge`   | Save something a bookkeeper knows and would otherwise lose between sessions. Anchored to the names it is about, so it surfaces when those names appear.                                                                                                                                                                                                      |
| `qb_confirm_knowledge` | A person confirms an entry, making it live.                                                                                                                                                                                                                                                                                                                  |
| `qb_list_knowledge`    | The company's knowledge, with anchors and confirmation state.                                                                                                                                                                                                                                                                                                |
| `qb_forget_knowledge`  | Retire an entry.                                                                                                                                                                                                                                                                                                                                             |
| `qb_write_playbook`    | Save a procedure — a month-end close order, a reconciliation sequence. Firm-wide unless a company is named.                                                                                                                                                                                                                                                  |
| `qb_confirm_playbook`  | A person confirms a playbook.                                                                                                                                                                                                                                                                                                                                |
| `qb_list_playbooks`    | Firm-wide and per-company playbooks.                                                                                                                                                                                                                                                                                                                         |
| `qb_run_playbook`      | Fetch a confirmed playbook to work through, with its `{placeholders}` filled in and the client knowledge it needs already in view. It hands back a procedure and posts nothing: every write inside it still goes through a plan and an approval.                                                                                                             |
| `qb_study_history`     | Read the mirrored back history — two years by default — and write down what it says about how this client actually works: how each vendor gets coded and how often it bills, whether class tracking is really used, which accounts have gone dormant, what month-end looks like. Findings land as **draft** knowledge for a person to confirm or throw away. |
| `qb_log_work`          | Append a dated work-log entry: what was done, why, and what remains open.                                                                                                                                                                                                                                                                                    |
| `qb_work_log`          | Read the work log, newest first.                                                                                                                                                                                                                                                                                                                             |

<Info>
  The run journal records what was posted in enough detail to reverse it. It
  cannot say which document a batch came from, what was decided, or what is
  still open — that is what the work log is for.
</Info>

## Reaching us

One tool writes to Zeno rather than to a client's books.

| Tool                 | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qb_contact_support` | Write to Zeno support from inside the chat — something broken, a capability that is missing, a question the assistant could not answer, billing, or plain feedback. Called without `confirm` it shows you the mail and sends nothing; `confirm: true` sends it. The report carries your firm, the build and which AI client it came from, so nobody has to ask; it is filed under the account that authorized that client, a copy lands in their inbox, and replying to it reaches a person. It keeps working when a subscription has lapsed. |
