Hello everyone,
During Zoho Books implementations, one common challenge is updating a large number of existing records. The current options are usually:
- Update records manually from the UI using Mass Update (with limited batch size).
- Update records one by one through code using the API.
For large data corrections, migrations, or post-implementation changes, manually updating records is not practical, so I created a Node.js utility that safely performs bulk custom-field updates through the Zoho Books API.
The workflow
- Create a custom view containing the records that need to be updated.
- Export the records and extract their IDs into a text file (one ID per line).
- Point the script at the IDs file.
- Define the custom fields and new values in
.env. - Run the migration in three stages:
probe → dry-run → run.
Alternatively, instead of exporting IDs manually, you can write a small search function that retrieves the records you need and generates the IDs file automatically.
What the script supports
- Multiple custom-field updates in the same request.
- Any Books module (recurring invoices, invoices, contacts, bills, ...) via configuration — no code changes.
- Zero-ceremony OAuth: you provide only the Self Client grant code — the script exchanges it for a refresh token on first run, persists it locally, and mints access tokens automatically from then on. No manual token calls, no hardcoded tokens.
- Automatic re-refresh if Zoho invalidates the access token mid-run (401 handling).
- Request timeouts, retry with backoff for HTTP 429 and 5xx (honours
Retry-After). - Canary update: one record is updated and verified with a follow-up GET before the batch starts — a typo in a dropdown value aborts after one record, not after thousands.
- Progress milestones roughly every 10% of the batch, with a live ETA (the initial estimate is measured from the canary request's actual round-trip, not guessed).
- Resume capability: every outcome is appended to
results.jsonl; re-running skips records already updated successfully. A token problem or a network drop mid-run costs nothing. - Failed-ID export (
failed_ids.txt) for targeted retry.
Configuration
Everything lives in .env. You need exactly: data center, org ID, client ID/secret, a Self Client grant code, the module, the IDs file, and the fields to set — nothing else:
ZB_DC=eu
ZB_ORG_ID=123456789
ZB_CLIENT_ID=1000.xxxxx
ZB_CLIENT_SECRET=xxxxx
ZB_AUTH_CODE=1000.xxxxx
ZB_MODULE=recurringinvoices
ZB_IDS_FILE=invoice_ids.txt
ZB_THROTTLE_MS=700
ZB_FIELDS=[{"api_name":"cf_status","value":"Approved"},{"api_name":"cf_sync_date","value":"2026-07-16"}]
ZB_AUTH_CODE is the grant code from the API console (Self Client → Generate Code, with the scopes below). It is single-use and expires within 3–10 minutes, so run the script right after generating it — the first run exchanges it for a permanent refresh token and saves it to .zb_token_store.json. Add both .env and .zb_token_store.json to .gitignore, and revoke the client when the migration is done.
Gotchas worth knowing:
ZB_FIELDS must stay on a single line — dotenv does not parse unquoted multi-line values.ZB_DC must match the data center the client was created on. A client from api-console.zoho.eu will not authenticate against accounts.zoho.com.- If the exchange fails with
invalid_code, the grant code expired or was already consumed — generate a fresh one and re-run immediately.
ZB_MODULE is the URL path segment (recurringinvoices, invoices, contacts, ...). Note that Books responses wrap the record in a singular root key (invoice, recurring_invoice, ...) that doesn't match the URL segment — the script auto-detects it from the first GET, so you don't have to know this.
Usage
Probe the configuration and field mapping (read-only — this also performs the one-time grant-code exchange on first run):
bash
node zoho-books-bulk-cf-update.mjs probe
Update and verify one record, then stop:
bash
node zoho-books-bulk-cf-update.mjs dry-run
Execute the complete migration:
bash
node zoho-books-bulk-cf-update.mjs run
Sample run output:
48 IDs total · 0 already ok · 48 pending
auto-detected response entity key: "invoice"
Probe 639896000003678005: custom_fields present: cf_status, cf_sync_date, ...
cf_status → customfield_id 639896000000729241 (current: "Draft")
Canary update on 639896000003678005 ...
Canary verified.
Small batch (47 records) — throttle lowered to 300 ms.
1/48 · ETA 1.1 min
5/48 · ETA 1.0 min
10/48 · ETA 0.9 min
...
48/48 Done · ok=48 fail=0
Implementation details
The update process intentionally runs sequentially instead of firing parallel requests, to respect the per-minute API limit (100 requests/min per organization), avoid failures caused by throttling, and keep the migration predictable. The default 700 ms delay keeps the rate at roughly 85 requests/min. Batches of 90 records or fewer physically cannot breach the per-minute cap, so the script speeds those up automatically.
One detail that matters across orgs: custom fields in the update payload are addressed by customfield_id where possible. The script GETs one record first, resolves each api_name to its customfield_id, and only falls back to api_name addressing if the field is not present on the sample record.
Required scopes:
ZohoBooks.invoices.READ
ZohoBooks.invoices.UPDATE
(or the equivalent scopes for the module you are updating — always least-privilege rather than ZohoBooks.fullaccess.all)
Production considerations
- Mind the daily API cap as well as the per-minute one — it varies by Books plan. A 10,000-record migration may need to be split across days on lower plans.
- Dropdown custom fields must receive a value that matches an option exactly (spacing, hyphens, casing — especially with non-Latin characters). The canary catches this before the batch runs.
- An in-memory ID list is fine into the tens of thousands; the point of
results.jsonl is durability — progress survives crashes, token expiry, and Ctrl+C. - For extremely large or recurring migrations, the same logic can move into a queue-based Node.js worker where you control execution time, retry strategy, parallelism, and monitoring.
Where this is useful
- Updating custom fields after migrations.
- Fixing incorrectly imported data.
- Updating integration-generated records.
- Applying bulk corrections after changing business logic.
- Cleaning up data after implementation projects.
Sharing this pattern because bulk updates are a common challenge when working with the Zoho Books API. Script and example .env attached.
Recent Topics
Why can't we choose Fixed Asset account for Purchased Items? (eTims issue?)
Hello, When the company purchase items not for sale and not supposed to be in the inventory stock, like equipment for operational use, there is no way to access the Fixed Asset accounts in the drop down list. Is that an eTims limitation again? Or something
"Track Inventory for this item" is forced checked by default for goods items (eTims issue?)
Hello, Since connecting our Zoho books to eTims (Kenya) the "Track Inventory for this item" is forced checked by default (eTims issue?) in the Item creation page for any type of goods. So when purchasing anything that the company does not intend to sale,
Zoho CRM Functions: Redesigned Interface, Rich Analytics, and Multi-Language Support
Hello everyone! We have given Functions in Zoho CRM a major overhaul with a new interface that makes it easier to build, organize, monitor, and troubleshoot your functions throughout their lifecycle. As part of this revamp, we have also introduced a unified
Can you import projects into Zoho Projects yet?
I see some very old posts asking about importing project records into Zoho Projects. But I can't find anything up to date about the topic. Has this functionality been added? Importing tasks is helpful. But we do have a project where importing projects
reset password
Hi I need to reset my password and need help
Is it possible to set a value to a field based on certain conditions
Greetings Say i have a field that i want to set its value based on the value of another field.. for example if "number" field has value greater than 10, i want to set my field's value to X. Or if radio group had option 1 selected, then i want to set my
Native SMS and MMS Channel Support
89% of US consumers say they prefer to communicate with businesses via SMS / MMS (aka "texting"). (link) Unfortunately, Zoho Desk does not currently support the most popular channel for consumer communications in the United States. For those of us in
Zoho CRM Layout Rules: Nine New Actions, Profile-Based Execution, and Interactive Preview
Hello everyone, Availability: This feature is now available for customers in the JP and SA DCs. It is planned to be released for other customers in soon. We’re excited to announce powerful new enhancements to Layout Rules in Zoho CRM - a feature built
Global Sets for Multi-Select pick lists
When is this feature coming to Zoho CRM? It would be very useful now we have got used to having it for the normal pick lists.
How to add line breaks in formula with Concat?
I am trying to combine different fields with a formula field, but want to add line breaks. I.e. the current code looks like: Concat(${Contacts.Company_Name}, ' ' ,${Contacts.First_Name}, ' ' ,${Contacts.Last_Name}) And the result should be: John Doe
Introducing spam detection for webforms: An additional layer of protection to keep your Zoho CRM clean and secure
Greetings all, One of the most highly anticipated feature launches—Spam Detection in webforms—has finally arrived! Webforms are a vital tool for record generation, but they're also vulnerable to submissions from unauthenticated or malicious sources, which
Is Zoho Assist Secure Connect even practical for 1 person shop?
I was gun ho with Zoho Assist to replace my existing Remote Access product I have been using but I need to implement MFA on each unattended connection. Right now each of these connections in my other product has a rotating token that I have enter off
Join the Zoho Desk Virtual Classroom Training (VCRT)
Hello everyone, Have you heard about Zoho's Virtual Classroom Training (VCRT)? Zoho Desk's Virtual Classroom Training offers end-to-end training for Zoho Desk users. Join the VCRT and get hands-on guidance for setting up Zoho Desk and getting your business
Zoho CRM's revamped timeline view now extends to 3 years and support notes, filters, and email statuses
Editions: All DCs: All Release plan: These enhancements are being rolled out to customers in a phased manner. They will be available to most organizations by the end of May. For organizations with huge volumes of data, they will be available by the end
Zoho Mail App Unable to connect to server
Hi all, For the last two weeks, my Zoho Mail App on my iPhone which has worked fine up to this point has been unable to connect to the mail server. I can't access my emails even though I will get notification banners on the screen saying that they have been received. I can open Safari on my phone and then log in that way. This issue happens when I'm connected to wifi and on my phone data. I've tried deleting the app several times and reinstalling, and have updated to the latest version. But it still
Specific ListView Canvas on Canvas Home Page Always Loads Most Recent ListView, Not the One Specified
I had mentioned this to ZOHO, but I mainly wanted to see if others in the Community are also facing this problem. I created a Canvas ListView for a Custom Module, and then created a Canvas Home page (technically on a tab item, but I'm not sure if that
Add the Zoom Option to the Camera
Hi, I use the ZOHO Forms Camera so I can manage metadata, compression, etc. but this doesnt have the zoom parameter activated, so when we have photos in a tight space and want to use 0.5 for example, we can't, can this be enabled please. Thanks Dan
Manage booking pages from your Android phone
Hello everyone! We are happy to announce that users can now add and manage booking pages from their Bigin Android app. It is a multi-step form that users can create for purposes like booking appointments, scheduling calls or meetings, conducting webinars,
New UI - Color Preference Not Saving Permanently
Small, not very urgent problem I'd like to share regarding the new UI theme color. I've changed my theme preference to the default blue color around 20 times by now. It always reverts to a green color theme. I've followed the instructions of changing
Automating Employee Birthday Notifications in Zoho Cliq
Have you ever missed a birthday and felt like the office Grinch? Fear not, the Cliq Developer Platform has got your back! With Zoho Cliq's Schedulers, you can be the office party-cipant who never forgets a single cake, balloon, or awkward rendition of
Unbundle feature for composite items
We receive composite items from our vendors and sell them either individually or create other composite items out of them. So, there is a lot of bundling and unbundling involved with our composite items. Previously, this feature was supported in form
Inventory Barcode Creation - Add Picture of Item
Hi I am trying to set up bar code labels and include a picture of the item on the label - any idea on how to add that field to the barcode generator?
Gemini Action - Add "inineData" Support
Thank you guys for adding a Gemini action. I like Gemini models for the "grunt work" of AI, as they have the cheapest tokens of the trustworthy providers One thing that's missing in the action, though, is the ability to pass file data. If you pass a base64-encoded
Protect backed up and exported data using password encryption
Hello everyone, Protecting live data is crucial for any organization or product, as it contains sensitive customer information. However, protecting data does not end within the platform. Backup and export files often contain sensitive information and
Smarter holiday planning with yearly-specific Holiday Lists
Hello everyone! Managing holidays and business hours is now easier and more efficient. Holiday Lists now support holidays that fall on different dates every year, while business hours now supports more than one holiday list. This helps businesses manage
Zoho Projects - Cloning a task does not trigger task workflow when created
Hello! I have a Project where my team uses a set of tasks from a tasklist as templates, so we could simply clone it and drag it to another list in kanban view to avoid creating a new one from scratch. The process works well, but after cloning it the new
Best way to setup Inventory bin tracking for products with multiple boxes/crates
Hi - we need some advice from the community on setting up Items in the Inventory for products with multiple crates. We have large products in our warehouse where the product is delivered as two large (double pallet) crates. We've setup the Items for these
Cliq iOS can't see shared screen
Hello, I had this morning a video call with a colleague. She is using Cliq Desktop MacOS and wanted to share her screen with me. I'm on iPad. I noticed, while she shared her screen, I could only see her video, but not the shared screen... Does Cliq iOS is able to display shared screen, or is it somewhere else to be found ? Regards
not able to access Zoho from home WIFI
for some reasone i am not able to access Zoho on my laptop or my iphone while i am connected to my home Wifi, i am able to access these sites both on laptop as well as Iphone and associated apps on any other Wifi as well as when I am on my 4G connection
Five Guided Conversations Updates in Zoho Desk
Hello everyone, Guided Conversations is getting updates that make it easier to create more inclusive customer experiences, retain important conversation context, customize your widget, keep track of changes, and connect with external services. Here are
zoho desk
Hello, Did Zoho Desk have any issues today? Are tickets coming in late? I have an email account linked, and messages seem to be arriving with a delay—some email threads aren't coming through completely, and so on.
An important update for Zoho Cliq desktop users
The latest version of the Zoho Cliq desktop app (v1.8.0) will no longer be supported on macOS 10.15 Catalina and earlier versions. This is because the framework we use (Electron) no longer supports some older macOS versions. If you’re using macOS 10.15
Simplify eSignatures: Automate document workflows with Zoho WorkDrive
Hello everyone, We’re excited to invite you to our upcoming live webinar, where Zoho WorkDrive and Zoho Sign will come together to show you how to simplify and automate document workflows. From creating and collaborating on documents to approvals, e-signatures,
Function #7: Fetch a value from Deal in Zoho CRM to the related Estimate in Zoho Books
We're here with another function for those using the integration with Zoho CRM. You know that potentials can be linked to transactions in Zoho Books. But if you're including additional details about a Deal (potential) in Zoho CRM and you want to inherit
Turn off workflow Applied pop-up
hi We are new to Desk. I have a rule to set to "waiting for customer" when agent sends reply. This comes up every time. How to i turn off? Or am i seeing as admin.
Workflows being applied and the Large unwanted popup
When a workflow is being applied do to an action, then the Agent is left with a large Window asking if they would like the see the changes this workflow did. Is there any way to disable this prompt from appearing?
Maintenance notice for Zoho CommunitySpaces US data centers on August 23, 2026
Dear customers, We have scheduled a maintenance activity for Zoho CommunitySpaces in our United States (US) data centers on August 23, 2026, from 1:30 a.m. to 2:00 a.m. During this 30-minute maintenance window, Zoho CommunitySpaces will be temporarily
Knowledge base: The nitty-gritty of SEO tags
A well-optimized knowledge base with great SEO can benefit your company by allowing customers to find help articles and support resources using search engines. This enables customers to quickly and efficiently find the information they need without direct
zoho desk: Can tickets be created from Microsoft Teams messages?
I am trying to see if there is a way to integrate Microsoft teams with zohodesk. we have a few customers who prefer to communicate requests through Teams, and it would be great to create tickets when they do.
´´Send Email Reply´´ action does not work when the message body contains placeholders.
Hi Community, I am working on a workflow where the Customer contact is notified via email when their ticket status goes On Hold. To do that, I chose the Send Email Reply action, and the minute I add a placeholder, the workflow does not work and the ticket´s
Next Page