Kaizen #80 - COQL API - Part I

Kaizen #80 - COQL API - Part I

Hi everyone! Welcome back to another week of Kaizen

This week, we will discuss the COQL Queries in detail.

COQL (CRM Object Query Language) is a powerful query language based on SQL syntax that allows users to write their own queries and fetch records using module API names and field API names. In this post, we will discuss the operators supported by COQL in detail and also provide examples to help you understand better.  Please note that the information in the article holds true for version 4 of Zoho CRM APIs.

When should you use the Query API?

Use Query API when you want to query for a module's data and/or it's look up related data using various comparators, or for records that fall into a custom view without actually creating one. For example, if you want to query for all products in a specific price range, with a 5 star rating and sort the results by price, use the Query API. Similarly you can use Query API to query for records from cross-modules (linked via lookup field), such as filtering products based on the vendor's details. 

What types of queries are supported by COQL?

COQL supports only the SELECT query, which is used to select data from the CRM, based on the conditions specified by the clauses. 

Here is a sample query:
SELECT {field_api_names} FROM {module_api_name} WHERE {field_api_name} {comparator} {logical_operator} {value} ORDER BY {field_api_name} ASC/DESC LIMIT {limit} OFFSET {offset}

What are the clauses & aggregate functions supported by COQL?

WHERE - used to select records based on specific conditions.
FROM - specifies the module from which to fetch the records.
ORDER BY - used to sort the results in ascending or descending order.
LIMIT - used to limit the number of records returned by the query.
OFFSET - used to skip a specified number of records while retrieving the records.


{
 "select_query" : "select Last_Name, First_Name, Mobile, Final_Score from Leads where (Lead_Status = 'Not Contacted') ORDER BY Final_Score DESC LIMIT 5 OFFSET 10"
}


For example, the above query retrieves the Last_Name, First_Name, Mobile and Final_score of all Leads whose status equals 'Not Contacted'. The results will be sorted in descending order based on the Final_Score field, and only the 5 records after skipping the first 10 will be returned.

NOTE : You can also use the syntax "LIMIT offset, limit" to achieve the same result. For example :


{
 "select_query" : "select Last_Name, First_Name, Mobile, Final_Score from Leads where (Lead_Status = 'Not Contacted') ORDER BY Final_Score DESC LIMIT 5, 10"
}


Aggregate functions can perform calculations on a set of values and return a single value. 
SUM() - to get the sum of the values of an aggregate field in a module.
MAX() - to get the maximum value of an aggregate field.
MIN() - to get the minimum value of an aggregate field.
AVG() - to get the average value of the values of a field.
COUNT() - to get the number of records that satisfy the criteria.

Wildcard Character Support in COQL

In COQL queries, the only supported wildcard character is %. This % wildcard can be used with the like operator to achieve functionality similar to the contains, starts_with and ends_with operators. For instance, '%tech" queries for field values ending with tech, 'C%' queries for the values starting with C, and '%tech%' translates to contains 'tech'.

Supported field types and Comparators

The following table gives a gist of the field types whose data you can query for, and the comparators for each field type.
Field TypeComparators
Text and Picklist=, !=, like, not like, in, not in, is null, is not null
Lookup=, !=, in, not in, is null, is not null
Date, DateTime, Number, Currency=, !=, >=, >, <=, <, between, not between, in, not in, is null, is not null
Boolean=

Supported field types and Comparators

1) Text and Picklist Fields

Supported comparators : =, !=, like, not like, in, not in, is null, is not null. Please note that the like operator is used for starts_with, ends_with, contains, and not like operator is used for not contains

Sample Query 1: (=, like, in)

{
    "select_query": "SELECT First_Name, Last_Name FROM Leads WHERE (((Lead_Status = 'Pre-Qualified') and (Company like '%zylker%')) and Industry in ('Technology', 'ERP'))"
}

This SELECT query retrieves the First_Name and Last_Name of all Leads whose Lead_Status is Pre-QualifiedCompany contains zylker, and Industry is either Technology or ERP

Sample Query 2:(not in, like, not null)

{
"select_query": "SELECT First_Name, Last_Name FROM Leads WHERE (((Lead_Status not in ('Closed-Won', 'Closed-Lost')) and (Lead_Source like '%Web%')) and (Skype_ID is not null)) LIMIT 2"
}

This query will return the first name and last name of all leads whose lead status is not Closed-Won or Closed-Lost, whose Lead Source fields contains web, and whose Skype ID field is not empty.

Sample Query 3:( !=, not like, null)

{
    "select_query": "SELECT First_Name, Last_Name, Mobile FROM Leads WHERE (((Lead_Source != 'Webinar') and (City not like '%New York%')) and (Skype_ID is null))"
}

This query retrieves the first name, last name and mobile of leads where the lead source is not a webinar, the city is not New York, and the Skype ID field is empty or null.

2. Lookup Fields

=, !=, in, not in, is null, is not null are the supported comparators for lookup fields. If you want to get the name of the lookup field in the response, you must include the field API name in the query. Otherwise, the system will return only the ID of the field.

Sample Query 1: (=, not in, !=)

{
 "select_query": "select Last_Name, First_Name, Full_Name, Account_Name, Owner from Contacts where (((Account_Name.Account_Name != 'Zylker') and (Owner = 4876876000000327001)) and Vendor_Name.Vendor_Name not in ('Skytech','SR')) LIMIT 2"
}

This query retrieves the last name, first name, full name, account name, and owner of two contacts whose account name is not Zylker, whose owner ID is 4876876000000327001, and whose vendor name does not contain Skytech or SR.
Sample Response:
{
    "data": [
        {
            "First_Name": "John",
            "Full_Name": "John Wilson  ",
            "Owner": {
                "id": "4876876000000327001"
            },
            "Last_Name": "Wilson  ",
            "Account_Name": {
                "id": "4876876000000333089"
            },
            "id": "4876876000000333182"
        },
        {
            "First_Name": "Josephine",
            "Full_Name": "Josephine Darakjy",
            "Owner": {
                "id": "4876876000000327001"
            },
            "Last_Name": "Darakjy",
            "Account_Name": {
                "id": "4876876000000333090"
            },
            "id": "4876876000000333183"
        }
    ],
    "info": {
        "count": 2,
        "more_records": true
    }
}

In this query, the id of the account is returned but not the name since we have not specified the field API name in the query. To fetch the field name, specify the field API name in the query. Refer to the following sample query to know how.

Sample Query 2:  (in, is null, is not null)

{
    "select_query": "SELECT Deal_Name, Account_Name.Account_Name, Created_Time FROM Deals WHERE (((Account_Name.Account_Name in ('Grayson','Zylker')) and (Owner is not null)) and (Contact_Name is null)) ORDER BY Created_Time DESC LIMIT 2"
}

This query retrieves the Deal Name, Account Name, and Created Time of the 2 most recently created Deals whose Account Name contains Zylker or Grayson, and do not have a Contact Name associated with them but have a Deal Owner associated with them. The results will be ordered in descending order by the Created Time.
 
Sample Response:
{
    "data": [
        {
            "Deal_Name": "Westborne Deal",
            "Created_Time": "2023-04-06T10:04:02+05:30",
            "Account_Name.Account_Name": "Grayson",
            "id": "4876876000003548001"
        },
        {
            "Deal_Name": "Eastwing Deal",
            "Created_Time": "2023-04-05T19:10:55+05:30",
            "Account_Name.Account_Name": "Grayson",
            "id": "4876876000003526011"
        }
    ],
    "info": {
        "count": 2,
        "more_records": true
    }
}

In the same query, if you want to use the Account ID instead of the name, replace ((Account_Name.Account_Name in ('Grayson','Zylker')) with ((Account_Name in (4876876000001236083, 4876876000002799001)) to include the IDs instead of the field API names and the account names.
{
    "select_query": "SELECT Deal_Name, Account_Name.Account_Name, Created_Time FROM Deals WHERE (((Account_Name in (4876876000001236083, 4876876000002799001)) and (Owner is not null)) and (Contact_Name is null)) ORDER BY Created_Time DESC LIMIT 2"
}

3. Date, DateTime, Number, Currency Fields

=, !=, >=, >, <=, <, between, not between, in, not in, is null, is not null are the supported comparators for these fields.

Sample Query 1: (between, <, >)

{

    "select_query": "SELECT Deal_Name, Amount, Stage, Probability FROM Deals WHERE (((Closing_Date between '2023-01-01' and '2023-03-31') and (Probability < 99)) and (Amount > 10000))"

}

This query retrieves the deal name, amount, stage, and probability of all deals whose closing date is between January 1, 2023 and March 31, 2023, and whose probability is less than 99 and amount is greater than 10000.

Sample Response:
{
    "data": [
        {
            "Deal_Name": "Chapman Deal",
            "Amount": 2500000,
            "Probability": 97,
            "Stage": "Closed Won",
            "id": "4876876000003550011"
        }
    ],
    "info": {
        "count": 1,
        "more_records": false
    }
}

Sample Query 2: (<=, !=, >=)

{
    "select_query": "SELECT Product_Name, Qty_in_Stock, Vendor_Name, Cost_Price FROM Products WHERE (((Sales_End_Date <= '2023-04-30') and (Qty_in_Stock != 0)) and (Cost_Price >= 500))"
}

This query retrieves the product name, quantity in stock, vendor name, and cost price for all products whose sales end date is on or before April 30, 2023, whose quantity in stock is not zero, and whose cost price is greater than or equal to 500. Since Vendor_Name is a lookup field, only the ID will be returned in the response.
Sample Response
{
    "data": [
        {
            "Cost_Price": 2000,
            "Vendor_Name": {
                "id": "4876876000001039017"
            },
            "Product_Name": "Sigma",
            "Qty_in_Stock": 30,
            "id": "4876876000001036109"
        }
    ],
    "info": {
        "count": 1,
        "more_records": false
    }
}

Sample Query 3: (not between, is not, >)

{
    "select_query": "SELECT Last_Name, First_Name, Referred_By.Full_Name FROM Leads WHERE (((Final_Score not between 10 and 20) and (Annual_Revenue is not null)) and (No_of_Employees > 200)) LIMIT 1"
}

This COQL query selects the last name, first name, and the full name of the lead's referred by field, for one lead whose final score is not between 10 and 20annual revenue is not null and whose number of employees is greater than 200
Sample Response
{
    "data": [
        {
            "First_Name": "Chau",
            "Last_Name": "Kitzman",
            "id": "4876876000000333403",
            "Referred_By.Full_Name": "Simmons Truhlar"
        }
    ],
    "info": {
        "count": 1,
        "more_records": true
    }
}

Sample Query 4: (>, not in, =, is null)

{
   "select_query":"SELECT PO_Number, PO_Date, Status, Discount FROM Purchase_Orders WHERE (((PO_Date = '2023-04-06') and (Due_Date not in ('2023-04-10','2023-04-11', '2023-04-12'))) or ((Discount > 10) and (Requisition_No is null)))"
}

This query selects the PO_Number, PO_Date, Status, and Discount from the Purchase_Orders module where the PO_Date is equal to '2023-04-06' and Due_Date is not any of '2023-04-10', '2023-04-11', or '2023-04-12'; OR Discount is greater than 10 and Requisition_No is null. In this query, we have used both AND and OR operators to combine the clauses.
Sample Response
{
    "data": [
        {
            "Status": "Created",
            "PO_Date": "2022-05-10",
            "Discount": 9990,
            "PO_Number": "PO-JL-3876",
            "id": "4876876000001125176"
        },
        {
            "Status": "Created",
            "PO_Date": "2023-04-06",
            "Discount": 370.37,
            "PO_Number": "PO-DA-1932",
            "id": "4876876000003561019"
        }
    ],
    "info": {
        "count": 2,
        "more_records": false
    }
}

We hope you found this post useful and that it has given you a better understanding of COQL queries. In our next post, we will discuss the rest of the field types, aggregate functions with more examples, and provide more queries to help you get started.

If you have any questions or feedback, please let us know in the comments below, or write to us at support@zohocrm.com. We would love to hear from you! 

Additionally, if you have any questions about the COQL API or how to construct a query, kindly let us know in the comments.

Additional Reading:


    • Sticky Posts

    • Kaizen #197: Frequently Asked Questions on GraphQL APIs

      🎊 Nearing 200th Kaizen Post – We want to hear from you! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Kaizen #198: Using Client Script for Custom Validation in Blueprint

      Nearing 200th Kaizen Post – 1 More to the Big Two-Oh-Oh! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Celebrating 200 posts of Kaizen! Share your ideas for the milestone post

      Hello Developers, We launched the Kaizen series in 2019 to share helpful content to support your Zoho CRM development journey. Staying true to its spirit—Kaizen Series: Continuous Improvement for Developer Experience—we've shared everything from FAQs
    • Kaizen #193: Creating different fields in Zoho CRM through API

      🎊 Nearing 200th Kaizen Post – We want to hear from you! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Client Script | Update - Introducing Commands in Client Script!

      Have you ever wished you could trigger Client Script from contexts other than just the supported pages and events? Have you ever wanted to leverage the advantage of Client Script at your finger tip? Discover the power of Client Script - Commands! Commands
    • Recent Topics

    • ERROR CODE :512 - 5.4.4 DNS error:NXDOMAIN.

      Suddenly we cant send mail, we are getting this error for all outbound mail to multiple domains.
    • Can Zoho Flows repeat Actions more than once?

      I'm attempting to make an intentional Zoho Flow loop using the below layout. However, when "WithinLimit" condition is met, the program fails to execute the action "Get & Add Request Co..." again. Is this by design? Is Zoho Flows unable to repeat actions
    • Unveiling Cadences: Redefining CRM interactions with automated sequential follow-ups

      Last modified on 01/04/2024: Cadences is now available for all Zoho CRM users in all data centres (DCs). Note that it was previously an early access feature, available only upon request, and was also known as Cadences Studio. As of April 1, 2024, it's
    • customer data security

      We are exploring ways to enhance our within Zoho CRM. Our Goal: We want to fully integrate RingCentral with Zoho CRM to enable click-to-call functionality for our sales team. However, to comply with data privacy regulations and protect customer contact
    • Zoho Cliq not working on airplanes

      Hi, My team and I have been having this constant issue of cliq not working when connected to an airplane's wifi. Is there a reason for this? We have tried on different Airlines and it doesn't work on any of them. We need assistance here since we are constantly
    • Sync CRM inventory data with Zoho Books

      I just switched everything over to ZoHo books, but I am trying to find out why the CRM Estimates, Invoices, and Sales Orders created in ZoHo CRM are not then duplicated in ZoHo Books? I had Quickbooks before, and had to do everything twice, I thought
    • mask Customer phone number and agents cant see customer phone number

      Is there any way we can integrate Zoom Phone with Zoho CRM while ensuring that customer phone numbers remain masked? We need a solution where agents can make outbound calls but cannot see customer phone numbers. Please let us know if there is any solution
    • Email Reminders on Shared Calendars

      How do we turn off the setting that emails reminders to everyone who has accepted or declined a calendar invite? If 8 of us have been invited to the same meeting, we receive 8 notifications for every step of the process, from invitation to decision.
    • WebDAV / FTP / SFTP protocols for syncing

      I believe the Zoho for Desktop app is built using a proprietary protocol. For the growing number of people using services such as odrive to sync multiple accounts from various providers (Google, Dropbox, Box, OneDrive, etc.) it would be really helpful if you implemented standard protocols such as WebDAV / FTP / SFTP so that alternative inc clients can be used.
    • What's New in Zoho Inventory | Q2 2025

      Hello Customers, The second quarter have been exciting months for Zoho Inventory! We’ve introduced impactful new features and enhancements to help you manage inventory operations with even greater precision and control. While we have many more exciting
    • How to refresh a ticket view ?

      I am doing a widget where I send a rest api call to make a new draft to the ticket I am viewing. The issue is sometimes it refresh a ticket view and I can see inserted draft right away, but sometimes I do not see it even if it is inserted correctly and
    • Ugh! - Text Box (Single Line) Not Enough - Text Box (Multi-line) Unavailable in PDF!

      I provide services, I do not sell items. In each estimate I send I provide a customized job description. A two or three sentence summary of the job to be performed. I need to be able to include this job description on each estimate I send as it's a critical
    • Merge Items

      Is there a work around for merging items? We currently have three names for one item, all have had a transaction associated so there is no deleting (just deactivating, which doesn't really help. It still appears so people are continuing to use it). I also can't assign inventory tracking to items used in past transactions, which I don't understand, this is an important feature moving forward.. It would be nice to merge into one item and be able to track inventory. Let me know if this is possible.
    • Supervisor Rules - Zoho Desk

      Hi, I have set up a Supervisor Rule in Zoho Desk to send an email alert when a ticket has been on hold for 48 hours. Is there a way to change it so that the alert only sends once and not on an hourly basis? Thank you Laura
    • ResponseCode 421, 4.7.0 [TSS04] Messages from 136.143.188.51 temporarily deferred due to user complaints

      Had email bounce. Let me know if you can fix this. Thanks. Michael
    • Zoho Canvas - Custom templates for related lists

      Hi, I see that the example pages load always one of our related lists in a custom template, but I dont know how to work with that:  1) How can i make my own custom templates for related lists?  2) Where and how can i check out existing custom templates?
    • Automation #15: Automatically Adding Static Secondary Contacts

      Rockel is a top-tier client of Zylker traders. Marcus handles communications with Rockel and would like to add Terence, the CTO of Zylker traders to the email conversations. In this case, the emails coming from user address rockel.com should have Terence
    • New Zoho triggers Google Dangerous flag due toabnormal charcters

      Just signed up and doing my first email test. I sent it to my google email account but it got flagged as Dangerous" due abnormal characters. My DNS setup looks ok. Page snips attached Help Please Thanks, Rick DC PowerWorld
    • Is there a API to fetch tasks in a Board/Section

      I am writing a scheduled function that retrieves all the tasks and send an reminder on cliq. I cannot seem to find a API to fetch tasks (by user / board / section) What are the way to fetch tasks?
    • Having trouble fetching contents of Zoho Connect Feeds using the API, requesting alternative API documentation.

      I'm trying to retrieve feed/post data from Zoho Connect using the API but facing challenges with the current documentation. What I've tried: OAuth authentication is working correctly (getting 200 OK responses) Tested multiple endpoints: /pulse/nativeapi/v2/feeds,
    • Adding an Account Name to Tasks/Reminders

      Does anyone know how to add the related account name to a task?  When we look at the list of activities and when the reminders pop up, there is no way of quickly seeing who the account is. 
    • Triggering Zoho Flow on Workdrive File Label

      Right now Im trying to have a zoho flow trigger on the labeling/classification of a file in a folder. Looking at the trigger options they arent great for something like this. File event occurred is probably the most applicable, but the events it has arent
    • SendMail to multiple recipients

      Hi, I'm trying to send an email to a list of recipients.  Right now the "to" field is directed to a string variable. (List variables won't work here). In the string variable, how can I make it work? trying "user@app.com;user2@app.com" or "user@app.com; user2@app.com" just failed to send the emails. Ravid
    • Populate drop down field from another form's subform

      Hello, I found how to do that, but not in case of a subform. I have a Product form that has a subform for unit and prices. A product might have more than one unit. For example, the product "Brocoli" can be sold in unit at 3$ or in box of 10 at 25 $. Both
    • Usar o Inventory ou módulo customizado no CRM para Gestão de Estoque ?

      Minha maior dor hoje em usar o zoho é a gestão do meu estoque. Sou uma empresa de varejo e essa gestão é fundamental pra mim. Obviamente preciso que esse estoque seja visível no CRM, Inicialmente fiz através de módulos personalizados no próprio Zoho CRM,
    • Signup forms behaviour : Same email & multiple submissions

      My use case is that I have a signup form (FormA) that I use in several places on my website, with a hidden field so I can see where the contact has been made from. I also have a couple of other signup forms (FormB and FormC) that slight differences. All
    • getting error in project users api

      Hello, I'm getting a "Given URL is wrong" error when trying to use the Zoho Projects V3 API endpoint for adding users to a project. The URL I'm using is https://projectsapi.zoho.com/api/v3/portal/{portalid}/projects/{projectid}/projectusers/ and it's
    • Change total display format in weekly time logs

      Hi! Would it be possible to display the total of the value entered in the weekly time log in the same format that the user input? This could be an option in the general settings -> display daily timesheet total in XX.XX format or XX:XX.
    • Different Company Name for billing & shipping address

      We are using Zoho Books & Inventory for our Logistics and started to realize soon, that Zoho is not offering a dedicated field for a shipping address company name .. when we are creating carrier shipping labels, the Billing Address company name gets always
    • How to display historical ticket information of the total time spent in each status

      Hi All, Hoping someone can help me, as I am new to Zoho Analytics, and I am a little stuck. I am looking to create a bar chart that looks back over tickets raised in the previous month and displays how much time was spent in each status (With Customer,
    • Zoho Projects iOS app update: Global Web Tabs support

      Hello everyone! In the latest version(v3.10.10) of the Zoho Projects app update, we have brought in support for Global Web Tabs. You can now access the web tabs across all the projects from the Home module of the app. Please update the app to the latest
    • Zoho Community Weekend Maintenance: 13–15 Sep 2025

      Hi everyone, We wanted to give you a heads-up that Zoho Community will undergo scheduled maintenance this weekend. During this period, some community features will be temporarily unavailable, while others will be in read-only mode. Maintenance Window:
    • Agent Performance Report

      From data to decisions: A deep dive into ticketing system reports An agent performance report in a ticketing system provides a comprehensive view of how support agents manage customer tickets. It measures efficiency and quality by tracking key performance
    • Show both Vendor and Customers in contact statement

      Dear Sir, some companies like us working with companies as Vendor and Customers too !!! it mean we send invoice and also receive bill from them , so we need our all amount in one place , but in contact statement , is separate it as Vendor and Customer, 
    • URL validation

      We use an internal intranet site which has a short DNS name which Zoho CRM will not accept.   When attempting to update the field it says "Please enter a valid URL". The URL I am trying to set is http://intranet/pm/ Our intranet is not currently setup with a full DNS name and given the amount of links using the shortname probably isn't a feasible change for us.
    • Pourquoi dans zohobooks version gratuite on ne peut ajouter notre stock d'ouverture??

      Pourquoi dans zohobooks version gratuite on ne peut ajouter notre stock d'ouverture ??
    • How can I adjust column width in Zoho Books?

      One issue I keep running into is as I show or hide columns in reports, the column widths get weird. Some columns have text cut off while others can take a fourth of the page for just a few characters. I checked report layout guides and my settings, but
    • Invalid value passed for file_name

      System generated file name does not send file anymore - what is the problem?
    • Custom Function for Estimates

      Hey everyone, I was wondering if there was a way to automate the Subject of an estimate whenever one is created or edited: * the green box using following infos: * Customer Name and Estimate Date. My Goal is to change the Subject to have this format "<MyFirm>-Estimate
    • This domain is not allowed to add. Please contact support-as@zohocorp.com for further details

      I am trying to setup the free version of Zoho Mail. When I tried to add my domain, theselfreunion.com I got the error message that is the subject of this Topic. I've read your other community forum topics, and this is NOT a free domain. So what is the
    • Next Page