Kaizen #131 - Bulk Write for parent-child records using Scala SDK

Kaizen #131 - Bulk Write for parent-child records using Scala SDK

Hello and welcome back to this week's Kaizen!
Last week, we discussed how to configure and initialize the Zoho CRM Scala SDK. This week, we will be exploring the Bulk Write API and its capabilities. Specifically, we will focus on executing bulk write operations for parent-child records in a single operation, and how to do this using Scala SDK.

Quick Recap of Bulk Write API

Bulk Write API facilitates efficient insertion, updation, or upsertion of large datasets into your CRM account. It operates asynchronously, scheduling jobs to handle data operations. Upon completion, notifications are sent to the specified callback URL or the job status can be checked periodically.

When to use Bulk Write API?

  • When scheduling a job to import a massive volume of data.
  • When needing to process more than 100 records in a single API call.
  • When conducting background processes like migration or initial data sync between Zoho CRM and external services.

Steps to Use Bulk Write API:

  1. Prepare CSV File: Create a CSV file with field API names as the first row and data in subsequent rows.
  2. Upload Zip File: Compress the CSV file into a zip format and upload it via a POST request.
  3. Create Bulk Write Job: Use the uploaded file ID, callback URL, and field API names to create a bulk write job for insertion, update, or upsert operations.
  4. Check Job Status: Monitor job status through polling or callback methods. Status could be ADDED, INPROGRESS, or COMPLETED.
  5. Download Result: Retrieve the result of the bulk write job, typically a CSV file with job details, using the provided download URL.
In our previous Kaizen posts - Bulk Write API Part I and Part II, we have extensively covered the Bulk Write API, complete with examples and sample codes for the PHP SDK. We highly recommend referring to those posts before reading further to gain a better understanding of the Bulk Write API.
With the release of our V6 APIs, we have introduced a significant enhancement to our Bulk Write API functionality. Previously, performing bulk write operations required separate API calls for parent and each child module. But with this enhancement, you can now import them all in a single, operation or API call.

Field Mappings for parent-child records in a single API call

When configuring field mappings for bulk write operations involving parent-child records in a single API call, there are two key aspects to consider: creating the CSV file containing the data and constructing the input JSON for the bulk write job. 

Creating the data CSV file:

To set up the data for a bulk write operation involving parent-child records, you need to prepare separate CSV files - one for the parent module records, and one each for each child module records. In these CSV files, appropriate field mappings for both parent and child records need to be defined. 

The parent CSV file will contain the parent records, while the child CSV file will contain the child records. To make sure that each child record is linked to its respective parent record, we will add an extra column (MappingID in the image below) to both the parent and child CSV files. This column will have a unique identifier value for each parent record. For each record in the child CSV file, the value in the identifier column should match the value of the identifier of the parent record in the parent CSV file. This ensures an accurate relationship between the parent and child records during the bulk write operation.

Please be aware that the mapping of values is solely dependent on the mappings defined in the input JSON. In this case, the column names in the CSV file serve only as a reference for you. Please refer to the notes section towards the end of this document for more details.


Creating the CSV file remains consistent across all types of child records, and we have already discussed how each child record is linked to its respective parent record in the CSV file. To facilitate the same linkage in the input JSON, we have introduced a new key called parent_column_index. This key assists us in specifying which column in the child module's CSV file contains the identifier or index linking it to the parent record. In the upcoming sections, we will explore preparing the input JSON for various types of child records.

Additionally, since we have multiple CSV files in the zip file, we have introduced another new key named file_names in resources array. file_names helps in correctly mapping each CSV file to its corresponding module.

Ensure that when adding parent and child records in a single operation, the parent module details should be listed first, followed by the child module details in the resource array of the input body.

1. Multiselect Lookup Fields

In scenarios involving multiselect lookup fields, the Bulk Write API now allows for the import of both parent and child records in a single operation.
In the context of multiselect lookup fields, the parent module refers to the primary module where the multiselect lookup field is added. For instance, in our example, consider a multiselect lookup field in the Leads module linking to the Products module.

Parent Module : Leads 
Child module : The linking module that establishes the relationship between the parent module and the related records (LeadsXProducts)

Here are the sample files for the "LeadsXProducts" case:

Leads.csv (Parent)

LeadsXProducts.csv (Child)

Given below is a sample input JSON for this bulk write job. Please note that the index of the child linking column should be mapped under the key index, and the index of the parent column index should be mapped under parent_column_index

To map the child records to their corresponding parent records (linking module), you must use the field API name of the lookup field that links to the parent module. For example, in this case, the API name of the lookup field linking to the Leads module from the LeadsXProducts is Leads.

{
"operation": "insert",
"ignore_empty": true,
"callback": {
"method": "post"
},
"resource": [
{
"type": "data",
"module": { 
"api_name": "Leads" //parent module API name
},
"file_id": "4876876000006855001",
"file_names": [
"Leads.csv" //parent records CSV file
],
"field_mappings": [ // field mappings for the parent record fields
{
"api_name": "Company", //field API name
"index": 0 //index in the CSV file
},
{
"api_name": "First_Name",
"index": 1
},
{
"api_name": "Last_Name",
"index": 2
},
{
"api_name": "Email",
"index": 3
},
{
"api_name": "Phone",
"index": 4
}
]
},
{
"type": "data",
"module": { 
"api_name": "LeadsXProducts" //child module API name
},
"file_id": "4876876000006855001",
"file_names": [
"LeadsXProducts.csv" //child records CSV file
],
"field_mappings": [
{
"api_name": "Products",
"find_by": "id",
"index": 0
},
{
"api_name": "Leads", //field API name of the lookup field in the Linking Module
"parent_column_index": 5, // the index of the identifier column in the parent CSV file
"index": 1 //index of the identifier column in the child CSV file
}
]
}
]
}

The following is a sample code snippet for the Scala SDK, to achieve the same functionality. Find the complete code here.

var module = new MinifiedModule() // Create a new instance of MinifiedModule
module.setAPIName(Option("Leads")) // Set the API name for the module to "Leads"
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006899001")) // Set the file ID for the resource instance 
resourceIns.setIgnoreEmpty(Option(true))
var filenames = new ArrayBuffer[String] // Create a new ArrayBuffer to store file names
filenames.addOne("Leads.csv")
resourceIns.setFileNames(filenames) // Set the file names for the resource instance
// Create a new ArrayBuffer to store field mappings
var fieldMappings: ArrayBuffer[FieldMapping] = new ArrayBuffer[FieldMapping]
// Create a new FieldMapping instance for each field
var fieldMapping: FieldMapping = null
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Company"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
.
.
// Set the field mappings for the resource instance
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)
resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("LeadsXProducts"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006899001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("LeadsXProducts.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Products"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Leads")) //Specify the API name of the lookup filed in the Linking Module
fieldMapping.setParentColumnIndex(Option(5)) //Specify the index of the identifier column in the parent CSV file
fieldMapping.setIndex(Option(1)) //Specify the index of the identifier column in the child CSV file
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

2. Multi-User Lookup fields

In case of multi-user lookup fields, the parent module remains the module where the multi-user field is added. The child module is the lookup module created to facilitate this relationship.
For instance, let's consider a scenario where a multi-user field labeled Referred By is added in the Leads module, linking to the Users module.

Parent module : Leads 
Child module : The linking module, LeadsXUsers.

To get more information about the child module, please utilize the Get Modules API. You can get the details of the fields within the child module using the Fields API
Here is a sample CSV for adding a multi-user field records along with the parent records:

LeadsXUsers.csv

Please ensure that you create a zip file containing the corresponding CSV files, upload it to the platform and then initiate the bulk write job using the file ID. The values for index and parent_column_index will vary based on your specific CSV files.

To create a bulk write job using Create Bulk Write job API, add the following code snippet to your resource array.
{
"type": "data",
"module": { 
"api_name": "Leads_X_Users" // child module
},
"file_id": "4876876000006887001",
"file_names": [
"LeadsXUsers.csv" //child records CSV file name
],
"field_mappings": [
{
"api_name": "Referred_User",
"find_by": "id",
"index": 0
},
{
"api_name": "userlookup221_11", //API name of the Leads lookup field in LeadsXUsers module
"parent_column_index": 5, // the index of the identifier column in the parent CSV file
"index": 1 // the index of the identifier column in the child CSV file
}
]
}

To do the same using Scala SDK, add the following code snippet to your code:

resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Leads_X_Users"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006904001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("LeadsXUsers.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Referred_User"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("userlookup221_11"))
fieldMapping.setParentColumnIndex(Option(5))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

3. Subform data

To import subform data along with parent records in a single operation, you must include both the parent and subform CSV files within a zip file and upload it. In this context, the parent module refers to the module where the subform is added, and the child module is the subform module.

For instance, consider a subform named Alternate Address in the Leads module, with fields such as City and State

Parent module : Leads
Child module : Alternate_Address (api name of the Subform module). 

In the subform CSV file (Alternate_Address.csv), in addition to the data columns, include a column to denote the linkage to the parent record.
Once the zip file containing both the parent and subform CSV files is prepared, proceed to upload it to initiate the import process. When you create the bulk write job, ensure to specify the appropriate values for index and parent_column_index based on your specific CSV files in the input.

Here is a sample CSV for the subform data, corresponding to the parent CSV provided earlier.

Alternate_Address.csv

To create a bulk write job using Create Bulk Write job API to import the subform data, add the following code snippet to your resource array.

{
"type": "data",
"module": { 
"api_name": "Alternate_Address" //Subform module API name
},  
"file_id": "4876876000006915001",
"file_names": [
"Alternate_Address.csv" //child (subform) records CSV
],
"field_mappings": [
{
"api_name": "State",
"index": 0
},
{
"api_name": "City",
"index": 1
},
{
"api_name": "Parent_Id", //Leads lookup field in the subform module
"parent_column_index": 5,
"index": 2
}
]
}

To do the same using Scala SDK, add the following code snippet to your code:

resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Alternate_Address"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006920001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("Alternate_Address.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("State"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("City"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Parent_Id"))
fieldMapping.setParentColumnIndex(Option(5))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

4. Line Items

To import line items along with the parent records, an approach similar to handling subform data is used. The parent module is the module housing the parent records, while the child module corresponds to the line item field.

For instance, in the Quotes module, to import product details within the record, the child module should be Quoted_Items. 

Here is a sample CSV for importing the parent records to the Quotes module:

Quotes.csv

Given below is a sample CSV to add the product details in Quoted Items:

Quoted_Items.csv

Now to create a bulk write job for these records, here is a sample input JSON:

{
"operation": "insert",
"ignore_empty": true,
"callback": {
"method": "post"
},
"resource": [
{
"type": "data",
"module": { 
"api_name": "Quotes"
},
"file_id": "4876876000006949001",
"file_names": [
"Quotes.csv"
],
"field_mappings": [
{
"api_name": "Subject",
"index": 0
},
{
"api_name": "Deal_Name",
"find_by" : "id",
"index": 1
},
{
"api_name": "Quote_Stage",
"index": 2
},
{
"api_name": "Account_Name",
"find_by" : "id",
"index": 3
}
]
},
{
"type": "data",
"module": { 
"api_name": "Quoted_Items"
},
"file_id": "4876876000006949001",
"file_names": [
"Quoted_Items.csv"
],
"field_mappings": [
{
"api_name": "Product_Name",
"find_by" : "id",
"index": 0
},
{
"api_name": "Quantity",
"index": 1
},
{
"api_name": "Parent_Id",
"parent_column_index": 4,
"index": 2
}
]
}
]
}

To do the same using Scala SDK, add this code snippet to your file:

val bulkWriteOperations = new BulkWriteOperations
val requestWrapper = new RequestWrapper
val callback = new CallBack
callback.setUrl(Option("https://www.example.com/callback"))
callback.setMethod(new Choice[String]("post"))
requestWrapper.setCallback(Option(callback))
requestWrapper.setCharacterEncoding(Option("UTF-8"))
requestWrapper.setOperation(new Choice[String]("insert"))
requestWrapper.setIgnoreEmpty(Option(true))
val resource = new ArrayBuffer[Resource]
var resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
var module = new MinifiedModule()
module.setAPIName(Option("Quotes"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006953001"))
resourceIns.setIgnoreEmpty(Option(true))
var filenames = new ArrayBuffer[String]
filenames.addOne("Quotes.csv")
resourceIns.setFileNames(filenames)
var fieldMappings: ArrayBuffer[FieldMapping] = new ArrayBuffer[FieldMapping]
var fieldMapping: FieldMapping = null
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Subject"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Deal_Name"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Quote_Stage"))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Account_Name"))
fieldMapping.setIndex(Option(3))
fieldMapping.setFindBy(Option("id"))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)
resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Quoted_Items"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006953001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("Quoted_Items.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Product_Name"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Quantity"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Parent_Id"))
fieldMapping.setParentColumnIndex(Option(4))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

Notes : 

  • When importing a single CSV file (parent or child module records separately), field_mappings is an optional key in the resource array. If you skip this key, the field mappings must be defined using the column names in the CSV file. In such cases, the column names should correspond to the field API names. Additionally, all columns should be mapped with the correct API names, and there should not be any extra unmapped columns.
  • When importing parent and child records in a single API call, field_mappings is a mandatory key.
  • The identifier column in the parent and child CSV can have different column names, as the mapping is done based on the input JSON.

Points to remember

  • An uploaded file can be used for a single bulk write job only. If you want to retry the operation with the same data, upload the file again to generate a new file ID.
  • When adding parent and child records in a single operation, ensure that the parent module comes first, followed by the child module details in the resource array of the input body.
  • The parent and all child CSV files should be zipped into a single file and uploaded. You cannot use more than one zip file in a single bulk write job. 
  • Define appropriate mappings for both parent and child records using the parent_column_index and index key to establish the relationship.
  • Utilize the resources > file_names key to map the correct CSV with the appropriate module
  • For each parent in the parent records file:
    • By default, the limit for Subforms and Line Items is set to 200. While you can configure this limit for subforms in the UI, customization options are not available for Line Items.
    • MultiSelect Lookup fields have a maximum limit of 100. If you have more than 100 associations for a MultiSelect Lookup field, you may schedule additional bulk write jobs for the child records alone, importing 100 records at a time.
    • The maximum limit for Multi-User Lookup fields is restricted to 10
We hope that you found this post useful, and you have gained some insights into using the Bulk Write API effectively. If you have any queries, let us know in the comments below, or feel free to send an email to support@zohocrm.com. We would love to hear from you!

Recommended Reads :


    • Sticky Posts

    • Kaizen #217 - Actions APIs : Tasks

      Welcome to another week of Kaizen! In last week's post we discussed Email Notifications APIs which act as the link between your Workflow automations and you. We have discussed how Zylker Cloud Services uses Email Notifications API in their custom dashboard.
    • Kaizen #216 - Actions APIs : Email Notifications

      Welcome to another week of Kaizen! For the last three weeks, we have been discussing Zylker's workflows. We successfully updated a dormant workflow, built a new one from the ground up and more. But our work is not finished—these automated processes are
    • Kaizen #152 - Client Script Support for the new Canvas Record Forms

      Hello everyone! Have you ever wanted to trigger actions on click of a canvas button, icon, or text mandatory forms in Create/Edit and Clone Pages? Have you ever wanted to control how elements behave on the new Canvas Record Forms? This can be achieved
    • Kaizen #142: How to Navigate to Another Page in Zoho CRM using Client Script

      Hello everyone! Welcome back to another exciting Kaizen post. In this post, let us see how you can you navigate to different Pages using Client Script. In this Kaizen post, Need to Navigate to different Pages Client Script ZDKs related to navigation A.
    • Kaizen #210 - Answering your Questions | Event Management System using ZDK CLI

      Hello Everyone, Welcome back to yet another post in the Kaizen Series! As you already may know, for the Kaizen #200 milestone, we asked for your feedback and many of you suggested topics for us to discuss. We have been writing on these topics over the
    • Recent Topics

    • Deluge Learning Series – Best Practices in Deluge | December 2025

      We’re excited to bring you the next session of the Deluge Learning Series, focused entirely on writing cleaner, faster, and more reliable Deluge code. In this edition, we’ll dive deep into the essential best practices every Deluge developer should follow
    • Associate a Contact to a Campaign using deluge?

      If I want to add one record to another related list, which zoho function do I use? zoho.updateRelatedRecord is not it I don't think.  I simply want to take a "Contact" and associate it to a "Campaign" using deluge.  Can anyone help? contactId = 5122008000000796037;
    • Add "Groups" above "Users" in the Zoho Forms Left Menu

      Hi, We have Groups but you have to go to a Form and Share or use the Directory App to manage them, please add "Groups" above "Users" in the Zoho Forms Left Menu so you can manage them in 1 place within Zoho Forms too. Thanks Dan
    • Adding Taxes to paid consultations in Zoho Bookings

      I created a 'paid' consultation under Zoho Booking and integrated it with payment gateways for online/instant payment before a booking is done. How can I add 'taxes' to the price of consultation? I can add taxes to other Zoho apps (liks Books, Checkout,
    • Zoho CRM Reports Module on Mobil App

      I have the mobile app and the reports module doesn't appear in the sidebar for some reason. I saw a Youtube video where the user had the Reports module on mobile. Is there a setting to show it on mobile? Thanks.
    • Inquiry on Help Centre Tab Customisation

      Hi Zoho team, I’m wondering if it’s possible to further customise the Help Center tabs, specifically the descriptions under Knowledge Base, Community, and Tickets. While the current setup allows customising tab names, being able to tailor the descriptions
    • Passing a form object to a function

      Suppose I have a sort_order field in multiple tables and I want to increment it by +1 onCreate of a new record. Is there a way to pass the form object as an argument into the function to keep things DRY? The following function from Zia works, but I'd
    • Can you copy and paste a page within a form?

      I have been looking at trying to copy/duplicate a whole page within a form. I can't see how I can do this without having to add all the data in again. This is very time consuming. Any help would be great.
    • SMS to customers from within Bigin

      Hi All, Is there anyone else crying out for Bigin SMS capability to send an SMS to customers directly from the Bigin interface? We have inbuilt telephony already with call recordings which works well. What's lacking is the ability to send and receive
    • Unable to sort as Descending order

      Trying to change the sort order for a lookup field (checkboxes) from Ascending to Descending and keep getting an error in Deluge that the order must be Ascending Did anyone ran into this? Thanks Eyal
    • How do I copy an email message to one or more other folders?

      I can move a message to another folder using the "move to" option but I can't figure out how to copy a message. 
    • New feature request: Allow copy of email message to another folder

      Hello Zoho team, This is a suggested new feature to allow copy an email message to either another folder or the same folder. Within the same Zoho account. This is not a support request about "label". This is a suggested new feature to allow copies of
    • Hotmail is blocking the zoho mail IP

      Greetings, Since last Tuesday (5 days ago today) I wrote to Zoho support and I still haven't received a single response (Ticket ID: 2056917). Is this how you treat people who pay for your email service? I am making this public so that those who want to
    • Desk DMARC forwarding failure for some senders

      I am not receiving important emails into Desk, because of DMARC errors. Here's what's happening: 1. email is sent from customer e.g. john@doe.com, to my email address, e.g info@acme.com 2. email is delivered successfully to info@acme.com (a shared inbox
    • Creator Simplified #11: Create a custom button to download files

      Hey there! This time, let's see how to create custom buttons to download the files uploaded in the file upload field. Sample use-case A training app has a module that provides the materials for all the available courses. Students can click on the corresponding
    • Hide horizontal lines at bottom of form

      Hi I have a page with 3 forms embedded in html snippets. On each of the forms I can hide the submit button easily but I am left with the horizontal lines that bound that section and I cannot figure out to remove them (see below for the two sets of horizontal
    • Autosaving of Form Field

      HI can anyone suggest a way of autosaving or simulating an autosave function for a specific field in a form. The story is as follows. I have a bunch of technicians who write notes on how they do a repair. Sometimes they write for a couple of hours the troubleshooting process. If they click incorrectly, press ESC, Cancel or the browser crashes the information is lost which can be heartbreaking so my guys use notepad and then copy the information in. The only way around this is to click submit on the
    • Zoho Tracking Image location

      So we've been having an issue with tracking email opens. Specifically in Gmail. Our emails are not that long either, maybe 4 sections of image/250 characters of text/button per section.  But all my test accounts I used via Gmail we're showing opens. But then come to find out the tracking image is at the very bottom of the email. So If the message is clipped (It always just clips our social icons on the bottom) and the user doesn't click the show more button it never tracks the open.  Looking at other
    • AI Interview Insights: Turn Recorded Interviews into Quick Transcripts & Summaries

      Evaluating interviews shouldn’t require replaying long recordings or taking manual notes. With AI Interview Insights, you can now review complete transcripts and AI-generated summaries of your One-way (Recorded) interviews right inside Zoho Recruit. This
    • Employee Appraisal Applicability - Why is Date of Joining Hard-Coded?

      In the new (to me, at least) Performance Appraisal Cycle wizard, it's possible to set criteria to determine for whom the appraisal process should apply. This makes sense on its face. However, one MUST use the Date of Joining criterion as a filter. Why
    • Spotlight series #6: The Show app for Android TV has a new look!

      Hello everyone! We are delighted to introduce our revamped and redesigned Show app for Android TV.  Smart TVs are exploding in popularity. Android TV alone has over 110 million active monthly devices. Zoho Show, as part of a constant effort to improve
    • Ask the Experts 26: Brighten every customer interaction with Zoho Desk all year long

      Hello everyone, Greetings and welcome to Ask the Experts 26. As we wrap up 2025, we are excited to invite you to the 26th episode of our Ask the Expert series. 🎄The Merry Metrics Edition = Best of Zoho Desk [Best Practices + Holiday Automation + Year-End
    • Pricing calculator

      Alright, so I'm trying to create a pricing calculator/pricing report generator to use in a cabinet shop. I did all the logic and such, and the calculator works. I have a few other things that I would need it to be able to do though, I'll do my best to
    • Bug Details

      In the Bug detail the milestoneid is missing
    • Stop completed task lists from disappearing?

      Is there any way to stop projects from making tasks lists disappear when all the tasks in the list are completed? That's one of those little things where we're constantly fighting the product. For instance we have some projects which are ongoing - no start and end date. We use Kanban view to show the various task lists. We don't want the kanban list to disappear every time the items on it happen to be closed out. Thanks
    • Change of Blog Author

      Hi, I am creating the blog post on behalf of my colleague. When I publish the post, it is showing my name as author of the post which is not intended and needs to be changed to my colleague's name. How can I change the name of the author in the blogs?? Thanks, Ramanan
    • Allow customers to choose meeting venue and meeting duration on booking page

      My business primarily involves one-to-one meetings with my clients. Given the hybrid-work world we now find ourselves in, these meetings can take several forms (which I think of as the meeting "venue"): In-person Zoom Phone call I currently handle these
    • Booking outside of scheduled availability

      Is there a way for staff (such as the secretary) to book appointments outside of the scheduled availability? Right now to do this special hours must be set each time. There should be a quicker way. Am I missing something?
    • Operation Questions.

      Hello, I hope you are well. To explain a little, we are a company that sells services and products with a technical team responsible for installation and maintenance. Zoho FSM can be useful for the technical team, namely for the technical coordinator
    • Direct Access and Better Search for Zoho Quartz Recordings

      Hi Zoho Team, We would like to request a few enhancements to improve how Zoho Quartz recordings are accessed and managed after being submitted to Zoho Support. Current Limitation: After submitting a Quartz recording, the related Zoho Support ticket displays
    • Update date & time when a cell is edited

      Hi All, I am desiring to have a cell update with the current date and time when another cell is edited. Any ideas?  Thank you
    • Add "Groups" to "Share With" on Reports & All Entries

      Hi, On Forms we can share Publicly, with Specific Users And/Or Specific Groups or All Users. With Reports and All Entries we lack the "Groups" option, please add this as with many users this saves a lot of work. Thanks Dan
    • Add Pause / Resume Option to Zoho Quartz Recordings

      Hi Zoho Team, We would like to request an enhancement to Zoho Quartz recordings: the ability to pause and resume an ongoing recording. Current Limitation: At the moment, when recording an issue with Zoho Quartz, the recording continues even when we are
    • Custom Fields Not Showing Up in Invoice PDF Template Document Information

      I have added 2 custom fields under Sales > Invoices > Manage Custom Fields. They are set to show in all PDFs. However when I am editing my Invoice PDF template, i do not see the custom fields under Document Information.
    • Tracking Non-Inventory Items

      We have several business locations and currently use zoho inventory to track retail items (sales and purchase orders). We were hoping to use zoho inventory to track our non-inventory items as well (toilet paper, paper towels, etc). I understand that we
    • Can I use a Standalone CRM Function as the Callback URL For Async Export Data API?

      I am creating an export job using this API https://www.zoho.com/analytics/api/v2/bulk-api/export-data-async/create-export/view-id.html There is a "callbackUrl" key in the CONFIG object. I tried copying the URL for a standalone function in CRM which can
    • ZOHO Books

      Hi there, Why after I upgrade my Zoho invoice > Books then i wanted to add plugin which i cannot do. Please advise.
    • How is Your eCommerce Experience w/Zoho Inventory?

      First off, I'm SUPER grateful for the advent of Zoho Inventory and now the Zoho Commerce Suite. Overall, Inventory is a great product, especially for customers without an eCommerce presence. For eCommerce companies (especially those shipping more than ~10 packages/day), however, there are certain drawbacks that keep my clients from moving over to Zoho Inventory: Cons: 1. Invoice + Package Creation from Shopify/Other eCommerce Integrations: Zoho Inventory makes the somewhat perplexing decision to
    • Error AS101 when adding new email alias

      Hi, I am trying to add apple@(mydomain).com The error AS101 is shown while I try to add the alias.
    • Simplify Mass Replies with Predefined Templates and Snippets

      Hello everyone, We are happy to introduce a new enhancement to Mass Reply that helps agents respond to customers quickly and consistently. With the addition of Email Templates and Snippets in the reply window, agents can use predefined messages while
    • Next Page