Kaizen #92 - Bulk Read in PHP SDK

Kaizen #92 - Bulk Read in PHP SDK

Heya! Welcome back to the PHP SDK fold in our Kaizen series.

In this post, we will explore how to use bulk read APIs and how to structure the criteria format for different field data types in PHP SDK based on v4 APIs. This will ease your process of handling large volumes of data in an efficient and streamlined manner. 

What does Bulk Read API do?

The Bulk Read API helps you to fetch large volumes of data that meet specific criteria in a single request. Unlike the GET Records API , which has a limitation of 200 records per call, the Bulk Read API allows you to extract bulk data, 200k records, for data synchronisation purposes. This prevents the need for you to fire multiple API calls which can easily drain your daily credits.

This Bulk Read is asynchronous, thus the result for your request will not be available immediately. So, you will have to either poll the bulk read job status API to know the status or specify a callback URL for Zoho CRM to send notifications regarding the process. 

The CRM system processes your request and returns the results in either a CSV or ICS (for Meetings/Events module) zipped file. To download your result, use the job ID given in the response of bulk read job API .

This entire process can be wrapped into three stages as given below, 
  • Creating a Bulk Read Job 
  • Checking the status of a Bulk Read Job
  • Downloading the CSV/ICS data zip

Create a Bulk Read Job

1. Adding Callback URL

To get notified of the progress and results of the bulk read job, add a callback URL to the request body using the following format. 
$requestWrapper = new RequestWrapper();

$callbackVar = new CallBack();

$callbackVar->setUrl(" your_callback_url ");

$callbackVar->setMethod(new Choice("post"));

$requestWrapper->setCallback($callbackVar);
The method for callback URL is typically set to POST as it helps the client to send the required data along with the url to handle the callback appropriately.

2. Structuring a Query

A query comprises multiple parameters such as your desired module, fields, custom view ID, page value, file-type and criteria.

A criterion is typically a filter/condition used in a query to narrow down the data to your desired set of records. Criteria can include one or more conditions and you can combine them using group operators like 'and' and 'or' to create more complex filtering logic. 

Each condition in the criteria comprises three components.
  • Field - It refers to the field API name of the record, which you want to use for filtering purpose.
  • Comparator - It determines how the value of the specified field has to be evaluated.
  • Value - It represents the value of the field against which the record has to be evaluated.
This helps you to retrieve only the relevant records, thereby optimising the performance and reducing the amount of data transferred.

To enhance the understanding of how to structure a criterion, it is necessary to address these group operators and comparators before delving into it.

Group Operators 

Group Operators are used to perform logical operations on multiple conditions within a query. They help you in grouping multiple conditions together to create complex search criteria.The possible group operators are 'and' and 'or'.
  • and - It specifies that all conditions within the group must be satisfied for a record to be included in the query result.
  • or - It specifies that any of the conditions within the group can be satisfied for a record to be included in the query result.
These operators provide flexibility in constructing queries and retrieve the desired set of records from your CRM system with ease.

Comparators

Comparators are used in a query condition to specify the type of comparison that should be performed between a field and a value. They define the relationship between the field and the value and determine how the records are filtered. Refer to this help document to find the possible comparators with their field datatypes. 

An example of each datatype is given in PHP for your better understanding. 
Data Type
Example
  Number

$conditionVar = new Criteria();
$field = new MinifiedFields();
$field ->setAPIName("Amount");
$conditionVar>setField($field);
$conditionVar->setComparator(new Choice("greater_than"));
$conditionVar->setValue(10000);

  Multi-select 

$conditionVar = new Criteria();
$field = new MinifiedFields();
$field ->setAPIName("owner");
$conditionVar>setField($field);
$conditionVar->setComparator(new Choice("in"));
$owner = ["5545974393001", "5545974393011"]
$conditionVar->setValue($owner);

  DateTime                                   

$conditionVar = new Criteria();
$field = new MinifiedFields();
$field->setAPIName("Created_Time");
$conditionVar>setField($field);
$conditionVar->setComparator(new Choice("between"));
$createdTime = [date_create("2023-05-01T17:58:47+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get())), date_create("2023-06-01T17:58:47+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get()))];
$conditionVar->setValue($createdTime);

  Boolean

$conditionVar = new Criteria();
$field = new MinifiedFields();
$field ->setAPIName("Email_Opt_Out");
$conditionVar>setField($field);
$conditionVar->setComparator(new Choice("equal"));
$conditionVar->setValue(false);

  Lookup

$conditionVar = new Criteria();
$field = new MinifiedFields();
$field ->setAPIName("owner.last_name");
$conditionVar>setField($field);
$conditionVar->setComparator(new Choice("equal"));
$conditionVar->setValue("Boyle");

Structuring Simple Criteria

Below is a query format with a simple criterion of two conditions to filter your records from the given module. 

$criteriaVar = new Criteria();

$criteriaVar->setGroupOperator(new Choice("operatorValue"));

$conditionVar1 = new Criteria();

$fieldVar = new MinifiedFields();

$fieldVar->setAPIName("Field_API_Name");

$conditionVar1->setField($fieldVar);

$conditionVar1->setComparator(new Choice("comparatorValue"));

$conditionVar1->setValue("Field_Value");

$conditionVar2 = new Criteria();

$field = new MinifiedFields();

$field->setAPIName("Field_API_Name");

$conditionVar2->setField($fieldVar);

$conditionVar2->setComparator(new Choice("comparatorValue"));

$conditionVar2->setValue("Field_Value");

$criteriaVar->setGroup([$conditionVar1,$conditionVar2]);

$query->setCriteria($criteriaVar);

$requestWrapper->setQuery($query);

In the above format, the group operator is used for two different conditions.

Following is the json format of this simple criteria.
{
    "query": {
        "criteria": {
            "group_operator": "operatorValue",
            "group": [
                {
                    "comparator": "comparatorValue",
                    "field": {
                        "api_name": "Field_API_Name"
                    },
                    "value": "Field_Value"
                },
                {
                    "comparator": "comparatorValue",
                    "field": {
                        "api_name": "Field_API_Name"
                    },
                    "value": "Field_Value"
                }
            ]
        }
    }
}

Structuring Complex Criteria

To structure a criterion with four different conditions follow the below format.

//top-level group criteria with 2 different groups comprising of 2 different conditions each

$criteria = new Criteria();

$criteria->setGroupOperator(new Choice("operatorValue"));

//group1 with 2 different conditions

$groupVar1 = new Criteria();

$groupVar1->setGroupOperator(new Choice("operatorValue"));

$conditionVar11 = new Criteria();

$field11 = new MinifiedFields();

$field11->setAPIName("Field_API_Name");

$conditionVar11->setField($field11);

$conditionVar11->setComparator(new Choice("comparatorValue"));

$conditionVar11->setValue("Value");

$conditionVar12 = new Criteria();

$field12 = new MinifiedFields();

$field12->setAPIName("Field_API_Name");

$conditionVar12->setField($field21);

$conditionVar12->setComparator(new Choice("comparatorValue"));

$conditionVar12->setValue("Value");

$groupVar1->setGroup([$conditionVar11, $conditionVar12]);

//group2 with 2 different conditions

$groupVar2 = new Criteria();

$groupVar2->setGroupOperator(new Choice("operatorValue"));

$conditionVar21 = new Criteria();

$field21 = new MinifiedFields();

$field21->setAPIName("Field_API_Name");

$conditionVar21->setField($field21);

$conditionVar21->setComparator(new Choice("comparatorValue"));

$conditionVar21->setValue("Value");

$conditionVar22 = new Criteria();

$field22 = new MinifiedFields();

$field22->setAPIName("Field_API_Name");

$conditionVar22->setField($field22);

$conditionVar22->setComparator(new Choice("comparatorValue"));

$conditionVar22->setValue("Value");

$groupVar2->setGroup([$conditionVar21, $conditionVar22]);

//pushing the groups to the top-level group criteria

$criteria->setGroup([$groupVar1, $groupVar2]);

In the above format, two group variables ($groupVar1 and $groupVar2) are created, each representing a nested group of conditions. Both the groups are further assigned to the top-level group variable ($criteria). 

The json arrangement of the above format is given for your clarity.
{
    "query": {
        "criteria": {
            "group_operator": "operatorValue",
            "group": [
                {
                    "group_operator": "operatorValue",
                    "group": [
                        {
                            "comparator": "comparatorValue",
                            "field": {
                                "api_name": "Field_API_Name"
                            },
                            "value": "Field_Value"
                        },
                        {
                            "comparator": "comparatorValue",
                            "field": {
                                "api_name": "Field_API_Name"
                            },
                            "value": "Field_Value"
                        }
                    ]
                },
                {
                    "group_operator": "operatorValue",
                    "group": [
                        {
                            "comparator": "comparatorValue",
                            "field": {
                                "api_name": "Field_API_Name"
                            },
                            "value": "Field_Value"
                        },
                        {
                            "comparator": "comparatorValue",
                            "field": {
                                "api_name": "Field_API_Name"
                            },
                            "value": "Field_Value"
                        }
                    ]
                }
            ]
        }
     }
}

The default file type is CSV. To bulk read the Events module always prefer the ICS file type. Refer to this resource to fetch the custom view IDs, module and field API names. 

Below is a sample code for creating a bulk read job with compound criteria. The criteria follow this arrangement ((1 and 2) or (3 or 4)) of conditions.

<?php

use com\zoho\crm\api\bulkread\BulkReadOperations;
use com\zoho\crm\api\bulkread\CallBack;
use com\zoho\crm\api\util\Choice;
use com\zoho\crm\api\bulkread\Query;
use com\zoho\crm\api\bulkread\Criteria;
use com\zoho\crm\api\bulkread\RequestWrapper;
use com\zoho\crm\api\modules\MinifiedModule;
use com\zoho\crm\api\fields\MinifiedFields;
require_once "vendor/autoload.php";

class CreateBulkReadJob
{
public static function initialize()
    {
        // Add initialisation code
        // Refer to this article for more help
    }
    public static function createBulkReadJob(string $moduleAPIName)
    {
        $bulkReadOperations = new BulkReadOperations();
        $requestWrapper = new RequestWrapper();
        $callback = new CallBack();
        $callback->setUrl("https://www.callback.com/example");
        $callback->setMethod(new Choice("post"));
        $requestWrapper->setCallback($callback);

        //query
        $query = new Query();
        $module = new MinifiedModule();
        $module->setAPIName($moduleAPIName);
        $query->setModule($module);
        $query->setCvid("34770610087501");
        $query->setFields(["Last_Name"]);
        $query->setPage(1);

        //top-level group criteria with 2 different groups comprising of 2 different conditions each
        $criteria = new Criteria();
        $criteria->setGroupOperator(new Choice("or"));
        $criteriaList = array();

        //group1 with 2 different conditions
        $groupVar1 = new Criteria();
        $groupVar1->setGroupOperator(new Choice("and"));

        $conditionVar11 = new Criteria();
        $field11= new MinifiedFields();
        $field11->setAPIName("Last_Name");
        $conditionVar11->setField($field11);
        $conditionVar11->setComparator(new Choice("equal"));
        $conditionVar11->setValue("Boyle");
        
        $conditionVar12 = new Criteria();
        $field12 = new MinifiedFields();
        $field->setAPIName("Owner");
        $conditionVar12->setField($field12);
        $conditionVar12->setComparator(new Choice("in"));
        $owner = array("5545974000000393001","5545974000000393011");
        $conditionVar12->setValue($owner);
        $groupVar1->setGroup([$conditionVar11, $conditionVar12]);

         //group2 with 2 different conditions
        $groupVar2 = new Criteria();
        $groupVar2->setGroupOperator(new Choice("or"));

        $conditionVar21 = new Criteria();
        $field21 = new MinifiedFields();
        $field21->setAPIName("Company");
        $conditionVar21->setField($field21);
        $conditionVar21->setComparator(new Choice("equal"));
        $conditionVar21->setValue("Morlong Associates");
        
        $conditionVar22 = new Criteria();
        $field22= new MinifiedFields();
        $field22->setAPIName("Created_Time");
        $conditionVar22->setField($field22);
        $conditionVar22->setComparator(new Choice("between"));
        $createdTime = array(date_create("2023-04-15T17:58:47+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get())), date_create("2023-06-01T17:58:47+05:30")->setTimezone(new \DateTimeZone(date_default_timezone_get())));
        $conditionVar22->setValue($createdTime);
        $groupVar2->setGroup([$conditionVar21, $conditionVar22]);

         //pushing the groups to the top-level group criteria
        $criteria->setGroup($criteriaList);
        $query->setCriteria($criteria);
        $requestWrapper->setQuery($query);
        // $requestWrapper->setFileType(new Choice("ics")); for Events module
        $response = $bulkReadOperations->createBulkReadJob($requestWrapper);
        //Add your code to handle the response received in $response
        // For more details, refer here.
    }
}
CreateBulkReadJob::initialize();
$moduleAPIName = "Leads";
CreateBulkReadJob::createBulkReadJob($moduleAPIName);
?>

2. Status of a Bulk Read Job

To keep track of the status of your bulk read job, use the id provided in the details section of your bulk read job response. 

Here is a sample code for checking the status of a bulk read job.

<?php

use com\zoho\crm\api\bulkread\BulkReadOperations;

require_once "vendor/autoload.php";

class GetBulkReadJobDetails
{
public static function initialize()        
    {
        // Add initialisation code
        // Refer to this article for more help 
    }

    public static function getBulkReadJobDetails(string $jobId)
    {
        $bulkReadOperations = new BulkReadOperations();
        $response = $bulkReadOperations->getBulkReadJobDetails($jobId);
        //Add your code to handle the response received in $response
        // For more details, refer here.
    }
}
GetBulkReadJobDetails::initialize();
$jobId = "55459743108003";
GetBulkReadJobDetails::getBulkReadJobDetails($jobId);
?>

3. Download Bulk Read Result

To download your bulk read job result, use the job id mentioned in the bulk read job response. Additionally, provide the path of the destination folder where you would like to download the result. The result will be downloaded as a zip file containing CSV/ICS files.
Here is a sample code for downloading a bulk read job result.

<?php

namespace samples\bulkread;

use com\zoho\crm\api\bulkread\BulkReadOperations;

require_once "vendor/autoload.php";

class DownloadResult
{
public static function initialize()
    {
        // Add initialisation code
        // Refer to this article for more help  
    }
    public static function downloadResult(string $jobId, string $destinationFolder)
    {
        $bulkReadOperations = new BulkReadOperations();
        $response = $bulkReadOperations->downloadResult($jobId);
        $streamWrapper = $response->getObject()->getFile();
        fputs(fopen($destinationFolder . "/" . $streamWrapper->getName(), "w"), $streamWrapper->getStream());
        //Add your code to handle the response received in $response
        // For more details, refer here.
    }
}
DownloadResult::initialize();
$jobId = "55459743108003";
$destinationFolder = "/Downloads";
DownloadResult::downloadResult($jobId, $destinationFolder);
?>

We hope you found this post useful and engaging! 

If you have any queries, feel free to drop them in the comments section below or reach out to us directly at support@zohocrm.com. We value your thoughts and eagerly look forward to hearing from you.

Stay tuned for more enriching posts coming your way soon!

Cheers!

    • Sticky Posts

    • Kaizen #222 - Client Script Support for Notes Related List

      Hello everyone! Welcome to another week of Kaizen. The final Kaizen post of the year 2025 is here! With the new Client Script support for the Notes Related List, you can validate, enrich, and manage notes across modules. In this post, we’ll explore how
    • 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.
    • Recent Topics

    • Field Description is very small

      Hello, The field Description in the activity is very small. Why don't try open a new window, or a bigger popup, or increase the width of the "popup".  Example:
    • Function #53: Transaction Level Profitability for Invoices

      Hello everyone, and welcome back to our series! We have previously provided custom functions for calculating the profitability of a quote and a sales order. There may be instances where the invoice may differ from its corresponding quote or sales order.
    • Payment Vouchers

      Is there any Payment Vouchers in Zoho? How can we create payment for non-trade vendors, i.e. professional fees, rent, and payment to commissioner income tax?
    • API in E-Invoice/GST portal

      Hi, Do I have to change the api in gst/e-invoice portal as I use zoho e books for my e-invoicing. If yes, please confirm the process.
    • When I click on PDF/PRINT it makes the invoice half size

      When I click PDF / Print for my invoice in Zoho Books, the generated PDF appears at half size — everything is scaled down, including the logo, text, and layout. The content does not fill the page as it should. Could someone advise what causes Zoho Books
    • Search by contain letter in a column

      Hello, everyone I need a filter function that searches by letter in a cell, and it should be a macro. To clarify further, if I have a column with several names and I chose a search cell and what I want is search by a single letter, for example, "a" then
    • Enrich your contact and company details automatically using the Data Enrichment topping

      Greetings, I hope you're all doing well. We're happy to announce the latest topping we've added to Bigin: The Data Enrichment topping, powered by WebAmigo. This topping helps you automatically enhance your contact and company records in Bigin. By leveraging
    • Easier onboarding for new users with stage descriptions

      Greetings, I hope all of you are doing well. We're happy to announce a recent enhancement we've made to Bigin. You can now add descriptions to the stages in your pipeline. Previously, when creating a pipeline, you could only add stages. With this update,
    • Zoho Books Invoices Templates

      It would be really helpful to have more advanced features to customise the invoice templates in Zoho Books. Especially I´m thinking of the spacing of the different parts of the invoice (Address line etc.). If you have a sender and receiver address in
    • Can add a colum to the left of the item in Zoho Books?

      I would need to add a column to the left of the item column in Books. When i create custom fields, i can only display them to the right of the item.
    • Verifying Zoho Mail Functionality After Switching DNS from Cloudflare to Hosting Provider

      I initially configured my domain's (https://roblaxmod.com/) email with Zoho Mail while using Cloudflare to manage my DNS records (MX, SPF, etc.). All services were working correctly. Recently, I have removed my site from Cloudflare and switched my domain's
    • AI Bot and Advanced Automation for WhatsApp

      Most small businesses "live" on WhatsApp, and while Bigin’s current integration is helpful, users need more automation to keep up with volume. We are requesting features based on our customer Feedbacks AI Bot: For auto-replying to FAQs. Keyword Triggers:
    • Improved Contact Sync flow in Google Integration with Zoho CRM

      Hello Everyone, Your contact sync in Google integration just got revamped! We have redesigned the sync process to give users more control over what data flows into Google and ensure that this data flows effortlessly between Zoho CRM and Google. With this
    • 2025 Ask the Experts sessions wrap-up : Key highlights from the experts

      Here is a rewind journey of our Ask the Experts (ATE) Sessions, where we brought you expert insights and practical best practices together in one place. This recap highlights the key takeaways, learnings, and best practices from all these sessions so
    • How to disable the edit option in subform

      How to disable the edit option in subform
    • Adding non-Indian billing address for my Zoho subscription

      Hey Need help with adding a non-Indian billing address for my Zoho subscription, trying to edit the address to my Singapore registered company. Won't let me change the country. Would appreciate the help. Regards, Rishabh
    • Move record from one custom module to another custom module

      Is it possible to create a button or custom field that will transfer a record from one custom module to another? I already have the 'Leads' module used for the Sr. Sales department, once the deal is closed they convert it to the 'Accounts' module. I would like to create a 'Convert' button for a custom module ('Locations') for the department that finds locations for each account. Once the location is secured, I want to move the record to another custom module called 'Secured Locations'. It's basically
    • Convert Lead Automation Trigger

      Currently, there is only a convert lead action available in workflow rules and blueprints. Also, there is a Convert Lead button available but it doesn't trigger any automations. Once the lead is converted to a Contact/Account the dataset that can be fetched
    • Notes Not Saving

      Hello,  My notes are continuously not saving.  I make sure to save them, I know the process to save them.  It is not operator error.  I go back into a Leads profile a while later and do not see the previous notes that I have made.  I then have to go back and do unnecessary research that would have been in the notes in the first place.  Not a good experience and it is frustrating.  Slows me down and makes me do unnecessary work.  Please resolve.   As a quick heads up, deleting cookies is not a fix
    • Integration between "Zoho Sprints Stories" and "Zoho Projects Tasks/Subtasks"

      We have two separate teams in our organization using Zoho for project management: The Development team uses Zoho Sprints and follows Agile/Scrum methodology. The Infrastructure team uses Zoho Projects for traditional task-based project management. In
    • Prefill form with CRM/Campaigns

      I created a form in zForms and created prefill fields. I added this to the CRM and selected the fields so when sending from the CRM, the form works great. However, I want to use the same form in Campaigns and I want it to pull the data from CRM (which
    • Triggering a campaign automation from a Form

      I used Forms to create a lead form that is accessed by a button on my website. The field information flows into the CRM. However, I am trying to figure out how to use Campaign automations to start a workflow (series of campaign emails) that is triggered
    • Name changed in settings for mailbox but still not changed when typed in To field

      In the email account secretary@ i have updaetd the new staff members details but the old members name still appears when I type secretary@ in the To field. I cant work out where Zoho is finding the old name from. I have deleted the browser cache. If I
    • 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
    • Formula fields

      Zoho People now supports formula fields. This post illustrates it. Formula fields are fields whose value is calculated instead of being entered by the user. Using this, number, decimal and date manipulations can be done. The value of this field could be numeric or date depending on the output of the formula. In date manipulations, the result will be given in milliseconds, which you can format as per you need. The operators we support are +, - , *, /. Formula fields get recalculated automatically
    • Copy paste from word document deletes random spaces

      Hello Dear Zoho Team, When copying from a word document into Notebook, often I face a problem of the program deleting random spaces between words, the document become terribly faulty, eventhough it is perfect in its original source document (and without
    • Is it possible to use module field filters via URL parameters?

      It would be really convenient if I could quickly link to a filter. For reference, this is the filter functionality I'm referring to: https://help.zoho.com/portal/en/kb/crm/customize-crm-account/advanced-filters/articles/advanced-filters For example: My
    • Transitioning FESCO Bill Project to Zoho Sheets and Integration Options

      Hello Zoho Support, I'm considering transitioning my FESCO bill project from Google Sheets to Zoho Sheets and wanted to know if there are integration options to seamlessly migrate our existing work. You can view our platform here, any guidance would be
    • Support for Custom Fonts in Zoho Recruit Career Site and Candidate Portal

      Dear Zoho Recruit Team, I hope you're doing well. We would like to request the ability to use custom fonts in the Zoho Recruit Career Site and Candidate Portal. Currently only the default fonts (Roboto, Lato, and Montserrat) are available. While these
    • Lightbox Pop-up form

      I would like to embed my form using the lightbox pop up. I don't want it to load automatically. I want it to load when some clicks the button. I can see this option, however when I use the "show pop-up launch button" on the website, the button automatically
    • Data Processing Basis

      Hi, Is there a way to automate the data processing for a candidate every time an application arrives from job boards, without requiring manual intervention? That is, to automatically acquire consent for data processing. I've seen a workflow that allows
    • Lightbox Pop-up form

      I would like to embed my form using the lightbox pop up. I don't want it to load automatically. I want it to load when some clicks the button. I can see this option, however when I use the "show pop-up launch button" on the website, the button automatically
    • Zoho CRM for Everyone's NextGen UI Gets an Upgrade

      Hello Everyone We've made improvements to Zoho CRM for Everyone's Nextgen UI. These changes are the result of valuable feedback from you where we’ve focused on improving usability, providing wider screen space, and making navigation smoother so everything
    • Customer Management: #5 Never Let the Customer Slip

      When Rahul started Knight's Watch Consulting, his focus was simple: deliver good work and keep clients happy. He offered one-time consulting projects, monthly advisory retainers and usage-based support for growing clients. Business was steady, and customers
    • 10GB Email Storage Limits in Zoho CRM

      We’ve had Zoho One for almost 5 years and have always synced our emails from Gmail via IMAP… As of late, we’ve run into issues with our emails not syncing, due to being over the 10GB storage cap… What’s very odd is that we haven’t changed a thing? I know
    • Zoho Projects Android and iOS app update: Mobile device permission based on user profiles

      Hello everyone! We have brought in support for mobile device permissions based on the user profiles which are configured in organization level. Administrators can now configure the permissions on the web app(projects.zoho.com) by following the steps mentioned
    • Zoho Projects Android and iOS app update: Timesheet module is now renamed as 'Time Logs', delete option has been renamed to 'Trash'.

      Hello everyone! We have now renamed the Timesheet module as Time Logs and the delete option as 'Trash' on the Zoho Projects Android and iOS app. Time Logs Android: Time Logs iOS: Trash option Android: Trash option iOS: Please update the app to the latest
    • Zoho Mail app update: Manage profile picture, Chinese (Traditional) language support

      Hello everyone! In the latest version (v3.1.9) of the Zoho Mail app update, we have brought in support to manage profile picture. You can now set/ modify the profile picture within the app. To add a new profile picture, please follow the below steps:
    • Reminders for Article Approval

      Is there a way to send reminders for approvers to review articles and approve/deny them? I'm not seeing that option anywhere.
    • To print Multiple delivery notes in batches

      In Zoho Books, we can print a Delivery Note from an Invoice using the Print Delivery Note option, but it is non-editable and always prints all line items from the invoice. Our requirement is to deliver invoiced items in batches and print delivery notes
    • Next Page