@finopsbricks/fob-zb
v0.7.0
Published
Zoho Books from the terminal and from Node: a CLI for people and AI agents, plus a client library for workers. 26 resources, OAuth handled.
Maintainers
Readme
fob-zb — Zoho Books CLI and client library
Work with your Zoho Books organization from the terminal, from an AI agent, or from Node code. One package, two ways in:
- The CLI (
fob-zb): list, inspect and update invoices, bills, contacts, bank transactions and 23 other resources. Scriptable output (--json,--format csv), and agent-friendly. → finopsbricks.com/cli/fob-zb - The library (
import { fobZb }): the same resources as a Node client for workers and automated pipelines. OAuth token refresh, organization routing and data centers are handled. → Docs
Beta. Not affiliated with or endorsed by Zoho Corporation. "Zoho" and "Zoho Books" are trademarks of Zoho Corporation.
Install
npm install -g @finopsbricks/fob-zb
fob-zb getting-startedRequires Node.js 18 or later. If you use the fob dispatcher,
fob zb … and fob-zb … are the same command.
Connect your Zoho Books organization
You need a Zoho Self Client: a client ID, a client secret and a one-time grant code.
fob-zb getting-started prints these steps with the right links for your region.
- Open the Zoho API Console for your data center. Use
api-console.zoho.com(US),.eu,.in,.com.au,.jp,api-console.zohocloud.ca,.com.cnor.sa. A client only works in the region it was created in. - Choose Get Started (or Add Client), hover over Self Client, then Create Now → Create → OK. The Client Secret tab shows the Client ID and Client Secret.
- On the Generate Code tab, enter scope
ZohoBooks.fullaccess.all, a duration of 10 minutes and any description. Choose Create, pick your organization and copy the code. - Add a profile before the code expires. Each code works once only.
fob-zb config profiles add acme \
--region com \
--client-id 1000.XXXX --client-secret yyyy \
--grant-code 1000.zzzz # exchanged for a long-lived refresh token
fob-zb config profiles current # confirm the profile and organization
fob-zb invoices list --status overdueIf your Zoho login can see one organization, the profile picks it up automatically. If it
can see several, add lists them and asks which one to use. Without a terminal (scripts,
agents) it prints the list and the follow-up command; pass --organization-id <id> to skip the
question.
More organizations, same login: Zoho tokens belong to the user, not the organization. Reuse an existing profile's credentials instead of creating another Self Client:
fob-zb config profiles add second-org --from acme --organization-id 8927xxxxxxRevoking that refresh token (or deleting the Self Client) disconnects every profile that shares it. Full guide with screenshots: Zoho credentials.
Use the CLI
Grammar: fob-zb <resource> <action> [target] [options]. Run fob-zb <resource> to see its
actions, or fob-zb <resource> <action> --help for flags.
fob-zb invoices list --status overdue
fob-zb invoices show <id> # with line items
fob-zb invoices create --customer <id> --item <id> --quantity 2 --rate 5000
fob-zb contacts list --type customer
fob-zb bank-accounts list --format csv --fields account_name,account_type,balance
fob-zb vendor-payments create --vendor <id> --amount 1500 --date 2026-07-26 --paid-through <id> --bill <id>Every list supports --json, --fields, --format table|csv|json, --output <file> and
--page/--per-page. Formats csv and json fetch every page. --profile <name> (alias
--org) switches organization for one command.
27 resources, all with list and show:
- Sales/AR:
contacts,estimates,sales-orders,invoices,recurring-invoices,credit-notes,retainer-invoices,customer-payments - Purchases/AP:
bills,recurring-bills,vendor-credits,purchase-orders,expenses,recurring-expenses,vendor-payments - Banking:
bank-accounts,bank-transactions - Accounting:
chart-of-accounts,journals,items - Projects:
projects,time-entries - Settings:
organizations,users,taxes,currencies,contact-persons
Writes: create/edit/delete on contacts, items, chart-of-accounts and bank-accounts
(plus activate/deactivate); invoices (plus mark-sent, mark-void, email, writeoff,
cancel-writeoff); estimates, sales-orders, credit-notes and purchase-orders (plus
mark-*, submit, approve, email); bills (plus mark-open, mark-void). Also
vendor-payments create/delete; bank-transactions create, delete, categorize, match,
unmatch, uncategorize, exclude, restore; and recurring-* stop/resume. Deletes need
--yes. Try writes on a test organization first.
With an AI agent
Agents can drive the CLI directly. Tell your agent to run fob-zb getting-started first. It
reports an existing setup, or walks through connecting one without inventing credentials.
For question-only agents, consider a Self Client with read-only scopes.
Guide: Use with AI agents.
Use as a library
import { fobZb } from '@finopsbricks/fob-zb';
const zb = fobZb({
client_id, client_secret, refresh_token, // OAuth (see "Connect" above)
organization_id, // Zoho organization
region: 'com', // data center (default 'com')
});
const { data: overdue } = await zb.invoices.list({ status: 'overdue' });
const org = await zb.organizations.get(organization_id);Read the general ledger (library only for now): every account's totals in one call, then
the posted legs on any account. Legs are in base currency, and every leg of a transaction
shares its transaction_id.
const { data: accounts } = await zb.reports.generalLedger({ from_date: '2000-01-01', to_date: '2026-12-31' });
const { data: legs, truncated } = await zb.chartOfAccounts.getAllTransactions(accounts[0].account_id);Attach files (library only for now): bill attachments and expense receipts.
import fs from 'node:fs';
const bill = await zb.bills.create({ is_draft: true, vendor_id, bill_number, date, line_items });
await zb.bills.addAttachment(bill.bill_id, {
filename: 'invoice.pdf', data: fs.readFileSync('invoice.pdf'), contentType: 'application/pdf',
});
const expense = await zb.expenses.create({ account_id, paid_through_account_id, date, amount });
await zb.expenses.addReceipt(expense.expense_id, { filename: 'receipt.pdf', data, contentType: 'application/pdf' });is_draft: true in the body creates a bill in draft status. Zoho ignores status: 'draft'.
The client refreshes the one-hour access token from the refresh token on demand. Callers never mint tokens.
Credentials and configuration
Precedence: --profile flag → FOB_ZB_* env → current profile in ~/.fob/fob-zb/config.yml
(file mode 0600; override the directory with FOB_ZB_CONFIG_DIR).
The env path needs FOB_ZB_CLIENT_ID, FOB_ZB_CLIENT_SECRET, FOB_ZB_REFRESH_TOKEN and
FOB_ZB_ORGANIZATION_ID. FOB_ZB_REGION is optional. See .env.example.
Data centers: com, eu, in, com.au, jp, ca, com.cn, sa. The API host is taken
from the token response's api_domain.
Set FOB_DEBUG=1 to see stack traces. Error messages link to
troubleshooting.
Beta limits
bank-rulesandbase-currency-adjustmentsare not built yet.bank-transactions matchhas not been validated against a live bank feed (categorizeas a vendor payment has).- Statement import is library-only:
bankAccounts.importStatement,lastImportedStatement,deleteLastImportedStatement. - Attachments are library-only:
bills.addAttachmentandexpenses.addReceipt. There are no CLI commands for them yet, and no attachments on other resources. - Not yet supported: bulk operations, report endpoints, and a browser-based
auth login. Some writes are also missing:journalscreate,projectsandtime-entriescreate,vendor-creditsapply-to-bills, invoiceapply-credits, abank-accounts import-statementCLI command, and create on the settings resources.
Missing something you need? Open an issue.
Develop
See CONTRIBUTING.md.
npm install
npm test # jest (ESM)
npm run typecheck # tsc against jsconfig (@ts-check)License
Apache-2.0. See LICENSE and NOTICE.
