Beam Help
Get help now

How-to · Zoho CRM

How to retrieve duplicate records in Zoho

Identify and fetch duplicate records to maintain data quality.

Duplicate records in Zoho can be surfaced programmatically using a dedicated search endpoint, letting you identify and act on redundant data before it causes reporting or workflow issues.


Why this matters


Duplicate records inflate pipeline numbers, confuse support agents, and undermine automation rules that assume unique entries. Whether you are managing a product catalogue in Zoho Desk or contacts in Zoho CRM, catching duplicates early keeps your data clean and your processes reliable. As independent expert support (not official Zoho support), Beam Help walks you through the mechanics so your team can automate this check confidently.


Step-by-step


Step 1. Ensure your OAuth connection carries the correct scopes before making any API call. For Zoho CRM you need at minimum ZohoCRM.modules.ALL or equivalent read permissions, and for Zoho Desk you need Desk.search.READ alongside the relevant module scopes such as Desk.contacts.READ. [1]


Step 2. Authenticate and obtain a valid access token. The platform stores your connection details (access token, refresh token, API domain, and expiry timestamp) in a connection record keyed to your user account. Tokens are automatically refreshed roughly two minutes before they expire to prevent mid-request failures, so make sure your integration follows the same pattern. [5]


Step 3. If your token has expired, trigger a refresh by calling ZohoOAuth.refreshtokens() with the stored refresh token. On success, persist the new accesstoken and updated tokenexpiresat values back to your connection store so subsequent calls remain authenticated. [3]


Step 4. To retrieve duplicate records, issue a GET request to the following endpoint:


GET /api/v1/products/duplicate

This operation is identified internally as searchforduplicate_records and accepts an optional parameter dictionary (p) that you can use to filter or paginate results. [6]


Step 5. Pass any relevant filter parameters inside the p dictionary. The exact supported keys depend on your Zoho Desk configuration, but the parameter object is forwarded directly to the Zoho API, so consult your module's field list to narrow results (for example, by product category or date range). [6]


Step 6. Handle the response. A successful call returns a structured result object. If the result contains an error key, surface that message to the operator and halt further processing. If the result is clean, iterate over the returned records to review, merge, or flag them as needed. [8]


Step 7. When building links back to individual duplicate records in your UI, use the dc (data centre), crmorgid, deskorgid, and desk_portal values stored in your connection record to construct correct region-specific URLs. [2]


Common pitfalls


  • Missing scopes. If Desk.search.READ is absent from your OAuth grant, the duplicate search endpoint will return an authorisation error. Double-check the full scope list in your OAuth client configuration. [1]
  • Stale tokens. Calling the endpoint with an expired access token produces a 401 response. Build in proactive token refresh (at least 120 seconds before expiry) to avoid this mid-request. [5]
  • Wrong data centre. Zoho hosts data in multiple regions. If your apidomain points to zohoapis.eu but your client is configured for zohoapis.com, requests will fail silently or return empty results. Extract the data centre suffix from the apidomain stored during OAuth callback and use it consistently. [7]
  • Empty p parameter. Passing None instead of an empty dict {} for the p argument may cause unexpected behaviour depending on how the underlying HTTP client serialises the request. Default to {} when no filters are needed. [6]

What to check


  • Scopes are present: Confirm Desk.search.READ (and any module-level read scopes) appear in your active OAuth grant before calling the duplicate endpoint. [1]
  • Token is fresh: Verify that tokenexpiresat is at least 120 seconds in the future at the time of the request, and that your refresh logic updates the stored value on success. [5]
  • Endpoint returns data: Confirm the response from GET /api/v1/products/duplicate contains a non-empty result set and no error key before proceeding with any merge or deletion workflow. [6]

Sources cited

  1. [1] config.py
  2. [2] server.py: chat_stream
  3. [3] run_direct_tests.py
  4. [4] server.py: get_zoho_api
  5. [5] server.py: get_zoho_connection
  6. [6] GET /api/v1/products/duplicate
  7. [7] server.py: auth_callback
  8. [8] server.py: apply_plan
How to retrieve duplicate records in Zoho | Beam Help