Zoho Books API v3 Integration Guide

Learn how to generate Zoho Books OAuth 2.0 credentials, locate your Organization ID & Refresh Token, map ZIMRA tax rates, and enable real-time fiscal receipt writebacks.

Zoho Data Center Domains Supported
Mutero supports all regional Zoho Books data centers: US (`zoho.com`), EU (`zoho.eu`), IN (`zoho.in`), AU (`zoho.com.au`), CA (`zoho.ca`), and SA (`zoho.sa`).

1Generate OAuth 2.0 Client in Zoho API Console

Go to the official Zoho API Console ↗. Click Add Client and select Server-based Applications.

Zoho Client Registration — Field Guide

Field NameRequired Value
Client TypeServer-based Applications
Client NameMutero VFD
Homepage URLhttps://www.mutero.online
Authorized Redirect URIshttps://www.mutero.online/api/v1/vfd/integrations/zoho-books/callback

Click Create. In the Client Details tab, copy your Client ID, and click Client Secret to copy your secret.

2Where to Find Each Required Credential

1. Organization ID

  1. Log into your Zoho Books Dashboard.
  2. Click Settings (top right gear icon) > Organization Profile.
  3. Under your company name at the top, copy your Organization ID (e.g. 812345678).

Shortcut: You can also see your Organization ID directly in your browser address bar URL: https://books.zoho.com/app#/home?organization_id=812345678.

2. Data Center Domain

Look at your web browser address bar when logged into Zoho Books:

  • books.zoho.com → Select zoho.com (US / Global)
  • books.zoho.eu → Select zoho.eu (Europe)
  • books.zoho.in → Select zoho.in (India)
  • books.zoho.com.au → Select zoho.com.au (Australia)

3. Automated Access and Refresh Token Generation

1-Click Automated Authorization Setup

To generate and save your OAuth Refresh Token automatically when connecting Zoho Books in the Mutero Integrations Hub:

  1. Enter your Client ID and Client Secret obtained from your Server-based application in Zoho API Console.
  2. Copy the displayed Authorized Redirect URI (e.g. https://www.mutero.online/api/v1/vfd/integrations/zoho-books/callback) and save it in your Zoho API Console client under Authorized Redirect URIs.
  3. Once both Client ID and Client Secret are filled, click the Authorize Zoho ↗ button.
  4. Click Accept on the Zoho consent prompt. Zoho automatically redirects back to Mutero and generates your Refresh Token with zero manual token copy-pasting required.

3Token Generation Troubleshooting

Common OAuth Token Errors & Solutions

1. Server error in /oauth/v2/tokenThe endpoint supports only POST requests. GET requests directly from a browser URL bar are not allowed. Use cURL, Postman, or terminal commands.
2. invalid_code in /oauth/v2/tokenGrant codes are valid for 10 minutes and can only be used once. If expired or already used, generate a new code.
3. Refresh token missing in responseEnsure access_type=offline and prompt=consent are included when generating codes if requesting re-consent.
4. invalid_client or invalid_client_secretZoho requires parameters to be passed in the URL query string rather than a JSON body. Remove extra whitespace and verify your accounts domain matches your region (accounts.zoho.com, accounts.zoho.eu, etc.).

4Enter Credentials in Mutero Integrations Hub

Go to Integrations Hub in your Mutero Dashboard, locate Zoho Books API v3, and click Connect Zoho Books.

Required Configuration Fields Summary

Organization IDFound in Zoho Books Settings > Organization Profile (or browser URL).
Client ID & Client SecretGenerated in Zoho API Console (Server-based Application).
Refresh TokenGenerated via Self Client or Browser Authorization URL.
Data Center DomainMatches your login URL domain (`zoho.com`, `zoho.eu`, `zoho.in`, etc.).

5First-Time Zoho Transaction Preferences (ZIMRA FDMS Compliance)

When creating your first invoice in Zoho Books or configuring initial preferences under Settings > Preferences > Invoices, set your transaction preferences according to ZIMRA fiscalization rules:

Zoho Transaction Preferences — Recommended Settings

Zoho SettingRecommended SelectionZIMRA Compliance Requirement
Do you give discounts?At Line Item Level
OR At Transaction Level → Discount Before Tax
ZIMRA rules (RCPT024/026) calculate 15% VAT on the net price after discounts. Never select "Discount After Tax".
Items sold at rates inclusive of Tax?Tax Exclusive (or Tax Inclusive)Select based on your catalog pricing. Mutero automatically sets receiptLinesTaxInclusive accordingly.
Round Off TaxAt line level (Recommended)ZIMRA computes tax per line item. Rounding at the line level ensures Zoho's tax math matches ZIMRA's line item totals exactly without 1-cent discrepancies.
Rounding off in Sales TransactionsNo Rounding (Crucial)ZIMRA requires exact 2-decimal cent math (RCPT038). Rounding off total amounts can cause 1-cent checksum rejections by ZIMRA.
Additional ChargesAdjustments & Shipping Charges (Optional)Enable as needed. Ensure shipping rates carry appropriate VAT codes if taxable.
Currency & payment method

Mutero reads Zoho's native invoice currency_code (USD, ZiG/ZWG, etc.) — this is a standard Zoho field, not a Mutero custom field. Set the invoice currency in Zoho when you create the invoice. Payment method is not synced from Zoho; Mutero submits Cash to ZIMRA by default (required on every fiscal receipt).

Adding Tax Rates in Zoho Books (Settings > Taxes > + New Tax)

Create the three standard ZIMRA tax entries in Zoho Books under Settings > Taxes > Tax Rates > + New Tax:

Tax Name*Rate (%)*Compound Tax?Automatic ZIMRA Mapping
VAT (15%) or Standard Rate15%Unchecked (No)Standard Rate (ZIMRA Tax ID 1)
Zero Rated (0%) or Export0%Unchecked (No)Zero Rated (ZIMRA Tax ID 2)
Exempt or NOP0%Unchecked (No)Exempt (ZIMRA Tax ID 3)

Note: Do not check "This tax is a compound tax" as ZIMRA VAT is a single-tier tax. Mutero automatically maps these tax names to ZIMRA's numeric Tax IDs.

Unknown Zoho tax names never default to 15%
Unmapped Zoho tax rates are cancelled before ZIMRA submit — they do not silently become standard VAT. Map every Zoho tax name under Tax Mapping. When the Zoho contact has a tax registration number (TIN), Mutero sends ZIMRA buyerData (register name + TIN, RCPT043) on both webhook and Sync Now paths.
HS Code Configuration for Zero-Rated (0%) & Exempt Items

ZIMRA regulations require an 8-digit Harmonized System (HS) tariff code (e.g. 1001.11.00) for zero-rated or exempt sales to justify tax exemption during audit.

How Mutero handles HS codes for Zoho Books:

  • Automatic Default Mapping (Recommended): In Mutero Dashboard → Settings > Integrations > Tax Mapping, assign your fallback 8-digit tariff code to your Zero-Rated tax mapping. All zero-rated items imported from Zoho Books will automatically inherit this 8-digit code.
  • Zoho Custom Fields (Per Item): In Zoho Books, under Settings > Preferences > Items > Custom Fields, add a text field named HS Code. Mutero automatically extracts this field during sync.
  • Standard 15% VAT & General Services: Items with standard 15% VAT that do not specify an HS code automatically default to ZIMRA fallback tariff 0000.00.00 to prevent 422 payload rejections.

6Automatic ZIMRA Receipt Writeback Behavior

Once connected, Mutero monitors Zoho Books for approved sales invoices. Upon fiscalization, Mutero automatically:

  • Signs the invoice payload using ZIMRA FDMS cryptographic keys.
  • Posts a comment to the invoice timeline in Zoho Books containing the ZIMRA Receipt Number and Verification QR Link.
  • Optionally updates configured custom fields (Custom Field Receipt Number and Custom Field Verification Link).

6bHow to issue a credit note

Easiest option: Mutero web app
If Zoho feels confusing, open the fiscalised invoice in the Mutero web app, then click Issue Credit Note. That handles the ZIMRA credit note for you. Use the Zoho steps below only when you also want the credit note recorded in Zoho Books.

To keep Zoho in sync, create the credit note in Zoho Books against an invoice Mutero has already fiscalised.

Steps in Zoho Books

  1. Open the original sales invoice (it should already show an FRN in Mutero).
  2. Click Credit Note (or create one from the Credit Notes module and link that invoice).
  3. Add a short reason in the notes / reference field.
  4. Save it (not as Draft).
What happens next
Sync Now or your Zoho webhook imports the credit note. Mutero fiscalises it and posts the FRN comment on the Zoho credit note timeline.

For real-time credit notes

  1. Reuse the same Mutero webhook URL (with your business_id).
  2. Add a Zoho workflow on the Credit Notes module (Created / Edited), excluding Draft and Void.
  3. Attach the Mutero webhook action.

7Auto-Fiscalize Zoho Invoices (Required for Real-Time)

What this enables
When an invoice is saved (created or finalized) in Zoho Books, Zoho calls Mutero. Mutero imports the invoice, fiscalizes it with ZIMRA (if Auto Fiscalize is on), writes the FRN/QR back to Zoho, and refreshes your Mutero dashboard notifications, invoice list, stats, and usage meter in real time.

A. Enable Auto Fiscalize in Mutero

  1. Open Mutero Dashboard → Settings → Integrations (Integrations Hub).
  2. Confirm Zoho Books shows status Active and a default VFD device is selected.
  3. Turn Auto Fiscalize ON (default). When off, invoices are imported only and stay as drafts until you fiscalize manually.
  4. Complete Tax Mapping for your Zoho tax names (15% VAT, Zero Rated, Exempt).
  5. Copy your Business ID from the Integrations Hub / Business Profile — paste it as the Zoho webhook Parameter business_id (or into the query string if you paste the full URL from Integrations Hub).

B. Your Mutero Webhook URL

Critical: use www.mutero.online — Zoho does not follow redirects

Zoho Books will show a 308 Permanent Redirect in the workflow execution log if the webhook host is wrong. That means Mutero never received the invoice (no notification, no import, no fiscalisation).

  • Correct: https://www.mutero.online/...
  • Wrong: https://mutero.online/... (apex → www via 308; Zoho stops here)

Always copy the URL from Mutero → Integrations Hub, or type www. explicitly. Do not strip www.

In Zoho’s Edit Webhook screen, put the path in URL and add business_id as a separate Parameter (Zoho builds the preview query string for you):

Zoho Edit Webhook — URL field (no query string)bash
https://www.mutero.online/api/webhooks/zoho-books
Zoho Edit Webhook — Parameters rowbash
Key: business_id
Value: YOUR_MUTERO_BUSINESS_ID

URL Preview should look like: https://www.mutero.online/api/webhooks/zoho-books?business_id=YOUR_MUTERO_BUSINESS_ID. Replace the value with your Mutero Business ID (24 hex characters). Do not add a trailing slash or a trailing &.

Legacy path (also public, still requires www): https://www.mutero.online/api/v1/vfd/integrations/zoho-books/webhook

C. Create the Webhook (required first)

The webhook is a reusable Zoho Workflow Action. Create and save it before (or while) building the workflow rule. Associating it later only links this saved action — it does not define the URL.

Two ways to open the webhook editor
  1. Settings path: Zoho Books → Settings (gear) → AutomationWorkflow ActionsWebhooks + New Webhook.
  2. From a workflow rule: On the rule canvas, click + Immediate Actions → set Action Type to Webhooks → click the blue + Add New Action link (opens the same webhook creation form). After you save, select it and click Associate.

Fill Edit Webhook with these Mutero values (labels match the current Zoho Books UI):

Zoho webhook fieldExact value for Mutero
NameMutero ZIMRA Fiscalisation Webhook
ModuleInvoice
DescriptionOptional — e.g. “Notify Mutero when an invoice leaves draft for ZIMRA fiscalisation.”
MethodPOST
URLhttps://www.mutero.online/api/webhooks/zoho-booksHost must include www. Do not use apex mutero.online (308 redirect — Zoho does not follow it).
ParametersAdd one row: Key business_id · Value = your Mutero Business ID (24 hex). Zoho’s URL Preview should then show …/api/webhooks/zoho-books?business_id=…. Alternatively paste the full URL (with query) from Integrations Hub into URL and leave Parameters empty.
HeadersLeave empty (none required).
Authorization TypeSelf Authorization
Body TypeDefault Payload · Content-Type application/json;charset=UTF-8. Mutero accepts the invoice-only JSON Zoho sends (e.g. { "invoice": { ... } }). Root organization_id is optional when the integration is already configured.
  1. Click Save (or Save and Execute to smoke-test the URL).
  2. Confirm the webhook appears under Settings → Automation → Workflow Actions → Webhooks and that URL Preview uses www.mutero.online with business_id.
business_id vs organization_id
business_id belongs in the webhook URL / Parameters (Mutero business). organization_id is optional in the body — when present it must match the Zoho org saved in Mutero; when absent Mutero uses the stored integration credentials.

D. Create the Workflow Rule (trigger)

After the webhook exists, create the rule that decides when Zoho calls it. You do not need to email the customer to fiscalise — choose a criterion that matches how you finalize invoices in Zoho.

  1. Go to SettingsAutomationWorkflow Rules + New Workflow Rule.
  2. Module: Invoice. Name: Mutero ZIMRA Auto-Fiscalize.
  3. Under WORKFLOW RULE EXECUTION CONDITION: Workflow Type = Event Based · Action Type = Created or Edited · Execute the workflow when = Any selected field is updated → select Status · Execute when the record is = Edited each time.
  4. Criterion 1: Add criteria Yes, then pick one of the options below (recommended first).
Recommended (no email required): Status isn’t Draft

Criterion: Status isn’t Draft. Optionally add AND Status isn’t Void so cancelled invoices never fire the webhook.

This runs when an invoice leaves draft for any reason — Mark as Sent (without emailing), Approve, Paid, Overdue, Partially Paid, etc. You never have to send the invoice email just to fiscalise.

Other valid criteria
  • Status is Sent — works, but only after the invoice is marked Sent. Prefer Zoho Mark as Sent (no email) over “Send Email” if you use this criterion.
  • Status is Paid (or Overdue / Partially Paid) — fiscalise only after payment / aging, if that matches your process. Use OR conditions if you want several of these.
  • Created only (Action Type = Created) with criterion Status isn’t Draft — if you create invoices already non-draft in one step.

Example canvas (recommended): Rule Mutero ZIMRA Auto-Fiscalize · Module Invoice · Created or edited → Any selected field is updated → Status · Criterion 1 Status isn’t Draft → TRUE → Immediate Actions.

E. Associate the Webhook on the rule

On the Criterion 1 TRUE branch, attach the webhook you created in step C:

  1. Click + Immediate Actions (not Time Based Actions).
  2. In the Associate Immediate Actions panel, set Action Type to Webhooks.
  3. Under Name, select Mutero ZIMRA Fiscalisation Webhook. Confirm the URL / preview uses www.mutero.online and your business_id. (If the list is empty, use + Add New Action and complete step C, then return here.)
  4. Click Associate, then Save the workflow rule.

When done, Immediate Actions should list: Webhooks / Name: Mutero ZIMRA Fiscalisation Webhook / URL pointing at Mutero (www host).

F. Verify the setup
  1. In Zoho, create a test invoice with a mapped tax rate, then leave draft without emailing — e.g. Mark as Sent, or change status so it matches your criterion (Status isn’t Draft / Sent / Paid).
  2. In Zoho Workflow Logs, the webhook call must be 200 — not 308. A 308 means the URL still uses apex mutero.online; switch to www.mutero.online and retest.
  3. Within about a minute, open Mutero → Invoices — you should see ZB-… appear.
  4. Check the notification bell for “Zoho Books invoice received” / “Receipt fiscalized”.
  5. Open Sync Logs for status webhook_receivedsuccess.
  6. In Zoho, confirm a timeline comment with the ZIMRA FRN and verification link.
Draft invoices are skipped
Mutero ignores Zoho invoices with status draft or void. Prefer criterion Status isn’t Draft (and isn’t Void) so Zoho only calls Mutero on finalized invoices; Mutero also skips draft/void server-side as a safety net. Emailing the customer is never required for fiscalisation.