Documentation

Zoho Expense CLI

zoho-expense-pp-cli

Install

npx -y @mvanhorn/printing-press-library install zoho-expense

Installs the CLI binary and the agent skill for Claude Code, Codex, Cursor, Gemini CLI, Copilot, and more. Add --cli-only or --skill-only for one half. Requires Node.

Documentation

Upload receipts, auto-tag expenses from learned merchant memory, and close out the month in one command — the agent-friendly Zoho Expense CLI nobody else has built.

Zoho ships autoscan; this CLI ships everything that comes after — receipt dedup, learned merchant→category mapping, India GST splitting, and monthly report bundling. Built for AI agents that ingest invoices from an inbox on a cadence and need an idempotent, structured-output upload path. India-region by default; works against any Zoho datacenter by overriding the base URL.

Learn more at Zoho Expense.

Created by @amitav13 (Amitav Khandelwal).

Authentication

Zoho Expense uses OAuth 2.0 with a self-client authorization-code flow. Create a self-client at https://api-console.zoho.in/, generate a 10-minute authorization code, then run zoho-expense-pp-cli auth login --client-id <id> --client-secret <secret> (browser callback flow). The CLI exchanges the code for a long-lived refresh token (stored at ~/.config/zoho-expense-pp-cli/config.toml) and refreshes access tokens transparently. Tokens use the literal Zoho-oauthtoken Authorization prefix (not Bearer).

Quick Start

# Exchange the 10-min code for a refresh token
zoho-expense-pp-cli auth login --client-id $ZOHO_EXPENSE_CLIENT_ID --client-secret $ZOHO_EXPENSE_CLIENT_SECRET

# Set the active organization (first one in the list)
zoho-expense-pp-cli org use $(zoho-expense-pp-cli organizations list --json | jq -r '.[0].organization_id')

# Sync categories, reporting tags, projects, customers, expenses into the local store
zoho-expense-pp-cli sync

# Upload one receipt with hash-dedup and auto-tag
zoho-expense-pp-cli receipt upload ~/Downloads/uber-receipt.pdf --auto-tag

# Batch ingest a folder for AI consumption
zoho-expense-pp-cli invoice ingest ~/Downloads/october-invoices --auto-tag --agent

# Bundle the month into a report and submit
zoho-expense-pp-cli close --month 2026-10 --auto-submit

Unique Features

These capabilities aren't available in any other tool for this API.

Hermes-first ingestion

  • invoice ingest — Batch upload a folder of invoices to Zoho Expense, SHA256-dedup against the local store, poll autoscan in parallel, and auto-tag from learned merchant memory — the headline workflow for AI agents that ingest invoices from email.

    Agents that ingest invoices on a cadence need one command that handles dedup, autoscan, and tagging — not three.

    zoho-expense-pp-cli invoice ingest ~/Downloads/october-invoices --auto-tag --agent
    
  • receipt upload — SHA256-hash incoming receipts at upload, refuse duplicates (use --force to override).

    Idempotent receipt upload — safe to re-run on a folder agents have already processed.

    zoho-expense-pp-cli receipt upload ~/Downloads/uber-receipt.pdf --auto-tag
    
  • expense-untagged — List expenses missing category_id or project_id; --auto-fix applies the merchant→tag memory map and PUTs back to Zoho.

    One command turns 30 untagged scanned receipts into 30 tagged ones, using the user's own historical mapping.

    zoho-expense-pp-cli expense-untagged --auto-fix --agent
    

Local intelligence

  • merchant list — Build a local merchant→category/project/tag mapping from sync history; pre-fill tags on first sight of a new merchant.

    Solves Zoho's 'first-time merchant is always uncategorized' limitation with zero API calls.

    zoho-expense-pp-cli merchant list --agent --select merchant_name,category_name,seen_count
    
  • merchant map — Train the local merchant→category mapping for future auto-tag (one merchant at a time, or bulk from a CSV).

    Lets the user (or agent) explicitly seed the auto-tag map without waiting for sync history to learn it.

    zoho-expense-pp-cli merchant map 'AWS' --category Software --project Engineering
    

Monthly automation

  • close — Bundle a month's unreported expenses into an expense report in one shot — flags still-processing autoscans, flags untagged items, creates the report, attaches, optionally submits.

    The natural end of every monthly agent workflow — turn raw expenses into a submitted report without leaving the terminal.

    zoho-expense-pp-cli close --month 2026-10 --auto-submit --agent
    

India tax workflow

  • gst-split — India-specific: parse an expense's tax_id and line items, compute CGST/SGST (intra-state) or IGST (inter-state) shares, emit the breakdown or update the expense.

    Turns a monthly export into something a CA can directly file, without the user re-doing the math by hand.

    zoho-expense-pp-cli gst-split exp_1234567890 --emit-csv
    

Usage

Run zoho-expense-pp-cli --help for the full command reference and flag list.

Commands

currencies

Currencies and exchange rates

  • zoho-expense-pp-cli currencies create - Add a currency to the org
  • zoho-expense-pp-cli currencies delete - Delete a currency
  • zoho-expense-pp-cli currencies get - Get a currency
  • zoho-expense-pp-cli currencies list - List currencies configured in the org
  • zoho-expense-pp-cli currencies update - Update a currency

customers

Customers (contacts) expenses can be billed to

  • zoho-expense-pp-cli customers create - Create a customer
  • zoho-expense-pp-cli customers delete - Delete a customer
  • zoho-expense-pp-cli customers get - Get a customer
  • zoho-expense-pp-cli customers list - List customers
  • zoho-expense-pp-cli customers update - Update a customer

expense_categories

Expense categories used to classify expenses

  • zoho-expense-pp-cli expense_categories create - Create an expense category
  • zoho-expense-pp-cli expense_categories delete - Delete an expense category
  • zoho-expense-pp-cli expense_categories disable - Disable a category
  • zoho-expense-pp-cli expense_categories enable - Enable a category
  • zoho-expense-pp-cli expense_categories get - Get an expense category
  • zoho-expense-pp-cli expense_categories list - List expense categories
  • zoho-expense-pp-cli expense_categories update - Update an expense category

expense_reports

Expense reports — bundles of expenses submitted for approval and reimbursement

  • zoho-expense-pp-cli expense_reports approval-history - View the approval history of a report
  • zoho-expense-pp-cli expense_reports approve - Approve an expense report
  • zoho-expense-pp-cli expense_reports create - Create an expense report
  • zoho-expense-pp-cli expense_reports get - Get an expense report (includes attached expenses)
  • zoho-expense-pp-cli expense_reports list - List expense reports
  • zoho-expense-pp-cli expense_reports reimburse - Mark an expense report as reimbursed
  • zoho-expense-pp-cli expense_reports reject - Reject an expense report
  • zoho-expense-pp-cli expense_reports update - Update an expense report — used to attach more expenses

expenses

Expenses — the primary entity for an expense management CLI

  • zoho-expense-pp-cli expenses create - Create an expense (JSON body — for receipt upload use 'receipt upload')
  • zoho-expense-pp-cli expenses get - Get a single expense
  • zoho-expense-pp-cli expenses list - List expenses with rich filters (date range, status, user, category, project)
  • zoho-expense-pp-cli expenses merge - Merge multiple expenses (used to dedupe a scanned-receipt expense with a manual one)
  • zoho-expense-pp-cli expenses update - Update an expense — used to add category/project/tags after autoscan

organizations

Zoho Expense organizations you have access to

  • zoho-expense-pp-cli organizations get - Get organization details
  • zoho-expense-pp-cli organizations list - List organizations accessible to the authenticated user

projects

Projects expenses can be associated with

  • zoho-expense-pp-cli projects activate - Mark a project active
  • zoho-expense-pp-cli projects create - Create a project
  • zoho-expense-pp-cli projects deactivate - Mark a project inactive
  • zoho-expense-pp-cli projects delete - Delete a project
  • zoho-expense-pp-cli projects get - Get a project
  • zoho-expense-pp-cli projects list - List projects
  • zoho-expense-pp-cli projects update - Update a project

receipts

Upload receipts for autoscan

  • zoho-expense-pp-cli receipts - Upload a receipt file (multipart). Server queues for autoscan; poll expenses get for status.

reporting_tags

Reporting tags (custom tagging schema for expenses, e.g. cost center, billable, GST treatment)

  • zoho-expense-pp-cli reporting_tags activate - Activate a reporting tag
  • zoho-expense-pp-cli reporting_tags create - Create a reporting tag
  • zoho-expense-pp-cli reporting_tags deactivate - Deactivate a reporting tag
  • zoho-expense-pp-cli reporting_tags delete - Delete a reporting tag
  • zoho-expense-pp-cli reporting_tags get - Get a reporting tag
  • zoho-expense-pp-cli reporting_tags list - List reporting tags
  • zoho-expense-pp-cli reporting_tags list-options - List all options for a reporting tag
  • zoho-expense-pp-cli reporting_tags update - Update a reporting tag

taxes

Taxes (GST in India) applied to expenses

  • zoho-expense-pp-cli taxes create - Create a tax
  • zoho-expense-pp-cli taxes delete - Delete a tax
  • zoho-expense-pp-cli taxes get - Get a tax
  • zoho-expense-pp-cli taxes list - List taxes
  • zoho-expense-pp-cli taxes update - Update a tax

trips

Business trips that group related expenses

  • zoho-expense-pp-cli trips approve - Approve a trip
  • zoho-expense-pp-cli trips cancel - Cancel a trip
  • zoho-expense-pp-cli trips close - Close a trip (no further expenses can be added)
  • zoho-expense-pp-cli trips create - Create a trip
  • zoho-expense-pp-cli trips delete - Delete a trip
  • zoho-expense-pp-cli trips get - Get a trip
  • zoho-expense-pp-cli trips list - List trips
  • zoho-expense-pp-cli trips reject - Reject a trip
  • zoho-expense-pp-cli trips update - Update a trip

users

Manage users in the organization

  • zoho-expense-pp-cli users activate - Mark a user as active
  • zoho-expense-pp-cli users deactivate - Mark a user as inactive
  • zoho-expense-pp-cli users delete - Delete a user
  • zoho-expense-pp-cli users get - Get a user
  • zoho-expense-pp-cli users invite - Invite a user into the org
  • zoho-expense-pp-cli users list - List users
  • zoho-expense-pp-cli users me - Get the authenticated user's profile
  • zoho-expense-pp-cli users update - Update a user

Output Formats

# Human-readable table (default in terminal, JSON when piped)
zoho-expense-pp-cli currencies list

# JSON for scripting and agents
zoho-expense-pp-cli currencies list --json

# Filter to specific fields
zoho-expense-pp-cli currencies list --json --select id,name,status

# Dry run — show the request without sending
zoho-expense-pp-cli currencies list --dry-run

# Agent mode — JSON + compact + no prompts in one flag
zoho-expense-pp-cli currencies list --agent

Agent Usage

This CLI is designed for AI agent consumption:

  • Non-interactive - never prompts, every input is a flag
  • Pipeable - --json output to stdout, errors to stderr
  • Filterable - --select id,name returns only fields you need
  • Previewable - --dry-run shows the request without sending
  • Explicit retries - add --idempotent to create retries and --ignore-missing to delete retries when a no-op success is acceptable
  • Confirmable - --yes for explicit confirmation of destructive actions
  • Piped input - write commands can accept structured input when their help lists --stdin
  • Offline-friendly - sync/search commands can use the local SQLite store when available
  • Agent-safe by default - no colors or formatting unless --human-friendly is set

Exit codes: 0 success, 2 usage error, 3 not found, 4 auth error, 5 API error, 7 rate limited, 10 config error.

Freshness

This CLI owns bounded freshness for registered store-backed read command paths. In --data-source auto mode, covered commands check the local SQLite store before serving results; stale or missing resources trigger a bounded refresh, and refresh failures fall back to the existing local data with a warning. --data-source local never refreshes, and --data-source live reads the API without mutating the local store.

Set ZOHO_EXPENSE_NO_AUTO_REFRESH=1 to disable the pre-read freshness hook while preserving the selected data source.

Covered command paths:

  • zoho-expense-pp-cli currencies
  • zoho-expense-pp-cli currencies create
  • zoho-expense-pp-cli currencies delete
  • zoho-expense-pp-cli currencies get
  • zoho-expense-pp-cli currencies list
  • zoho-expense-pp-cli currencies update
  • zoho-expense-pp-cli customers
  • zoho-expense-pp-cli customers create
  • zoho-expense-pp-cli customers delete
  • zoho-expense-pp-cli customers get
  • zoho-expense-pp-cli customers list
  • zoho-expense-pp-cli customers update
  • zoho-expense-pp-cli expense_categories
  • zoho-expense-pp-cli expense_categories create
  • zoho-expense-pp-cli expense_categories delete
  • zoho-expense-pp-cli expense_categories disable
  • zoho-expense-pp-cli expense_categories enable
  • zoho-expense-pp-cli expense_categories get
  • zoho-expense-pp-cli expense_categories list
  • zoho-expense-pp-cli expense_categories update
  • zoho-expense-pp-cli expense_reports
  • zoho-expense-pp-cli expense_reports approval_history
  • zoho-expense-pp-cli expense_reports approve
  • zoho-expense-pp-cli expense_reports create
  • zoho-expense-pp-cli expense_reports get
  • zoho-expense-pp-cli expense_reports list
  • zoho-expense-pp-cli expense_reports reimburse
  • zoho-expense-pp-cli expense_reports reject
  • zoho-expense-pp-cli expense_reports update
  • zoho-expense-pp-cli expenses
  • zoho-expense-pp-cli expenses create
  • zoho-expense-pp-cli expenses get
  • zoho-expense-pp-cli expenses list
  • zoho-expense-pp-cli expenses merge
  • zoho-expense-pp-cli expenses update
  • zoho-expense-pp-cli organizations
  • zoho-expense-pp-cli organizations get
  • zoho-expense-pp-cli organizations list
  • zoho-expense-pp-cli projects
  • zoho-expense-pp-cli projects activate
  • zoho-expense-pp-cli projects create
  • zoho-expense-pp-cli projects deactivate
  • zoho-expense-pp-cli projects delete
  • zoho-expense-pp-cli projects get
  • zoho-expense-pp-cli projects list
  • zoho-expense-pp-cli projects update
  • zoho-expense-pp-cli reporting_tags
  • zoho-expense-pp-cli reporting_tags activate
  • zoho-expense-pp-cli reporting_tags create
  • zoho-expense-pp-cli reporting_tags deactivate
  • zoho-expense-pp-cli reporting_tags delete
  • zoho-expense-pp-cli reporting_tags get
  • zoho-expense-pp-cli reporting_tags list
  • zoho-expense-pp-cli reporting_tags list_options
  • zoho-expense-pp-cli reporting_tags update
  • zoho-expense-pp-cli taxes
  • zoho-expense-pp-cli taxes create
  • zoho-expense-pp-cli taxes delete
  • zoho-expense-pp-cli taxes get
  • zoho-expense-pp-cli taxes list
  • zoho-expense-pp-cli taxes update
  • zoho-expense-pp-cli trips
  • zoho-expense-pp-cli trips approve
  • zoho-expense-pp-cli trips cancel
  • zoho-expense-pp-cli trips close
  • zoho-expense-pp-cli trips create
  • zoho-expense-pp-cli trips delete
  • zoho-expense-pp-cli trips get
  • zoho-expense-pp-cli trips list
  • zoho-expense-pp-cli trips reject
  • zoho-expense-pp-cli trips update
  • zoho-expense-pp-cli users
  • zoho-expense-pp-cli users activate
  • zoho-expense-pp-cli users deactivate
  • zoho-expense-pp-cli users delete
  • zoho-expense-pp-cli users get
  • zoho-expense-pp-cli users invite
  • zoho-expense-pp-cli users list
  • zoho-expense-pp-cli users me
  • zoho-expense-pp-cli users update

JSON outputs that use the generated provenance envelope include freshness metadata at meta.freshness. This metadata describes the freshness decision for the covered command path; it does not claim full historical backfill or API-specific enrichment.

Health Check

zoho-expense-pp-cli doctor

Verifies configuration, credentials, and connectivity to the API.

Configuration

Config file: ~/.config/zoho-expense-pp-cli/config.toml

Static request headers can be configured under headers; per-command header overrides take precedence.

Environment variables:

NameKindRequiredDescription
ZOHO_EXPENSE_CLIENT_IDauth_flow_inputYesOAuth client ID from api-console.zoho.in self-client
ZOHO_EXPENSE_CLIENT_SECRETauth_flow_inputYesSet during initial auth setup.
ZOHO_EXPENSE_REFRESH_TOKENharvestedYesPopulated automatically by auth login.
ZOHO_EXPENSE_ORGANIZATION_IDper_callYesZoho Expense organization ID (sent as X-com-zoho-expense-organizationid header on every request)

Troubleshooting

Authentication errors (exit code 4)

  • Run zoho-expense-pp-cli doctor to check credentials
  • Verify the environment variable is set: echo $ZOHO_EXPENSE_ORGANIZATION_ID Not found errors (exit code 3)
  • Check the resource ID is correct
  • Run the list command to see available items

API-specific

  • HTTP 401 'authentication value invalid' — Run zoho-expense-pp-cli auth refresh — the access token expired (1h lifetime). If that fails, the refresh token may have rotated out (max 20 per user); re-run auth login with a fresh authorization code.
  • HTTP 404 / endpoint not found from a .com token — Region mismatch. Your token was issued by accounts.zoho.com but you're targeting www.zohoapis.in. Override base_url in the config file or set ZOHO_EXPENSE_REGION accordingly.
  • Receipt upload returns 'autoscan_status: Failed' — File format or size issue — max 5MB; JPG/PNG/PDF only. Multi-page PDFs scan but slower. Try re-saving the PDF as image-only and retry.
  • First expense for a new merchant has no category — Expected — Zoho only auto-categorizes after the merchant has been seen + categorized once. Use merchant map '<name>' --category ... to seed the local mapping, then expense-untagged --auto-fix.
  • HTTP 429 rate-limited — Zoho caps at 100 req/min per org. The CLI's adaptive limiter handles this automatically; if you see this surface, you're running parallel batches — drop concurrency.

Sources & Inspiration

This CLI was built by studying these projects and resources:

Generated by CLI Printing Press

For agents: pass /documentation/zoho-expense/agents.md to install this CLI from a prompt.