Retrieving reports in Zoho via the API involves authenticating your connection, calling the appropriate read tool, and following the response links back to the relevant records in your Zoho application.
Why this matters
When you need to pull report data programmatically — for dashboards, audits, or automated workflows — understanding how the retrieval pipeline works saves significant debugging time. Whether you are working with Zoho CRM or Zoho Desk, the underlying pattern of token management, tool execution, and link generation is consistent. As independent expert support (not official Zoho support), Beam Help walks you through each stage so you can adapt it to your own environment.
Step-by-step
Step 1. Establish and verify your Zoho connection.
Before any report data can be retrieved, the system must resolve a valid connection for your user account. The getzohoapi function looks up your stored connection record and, if the access token has expired, automatically calls ZohoOAuth.refreshtokens using the stored refresh token, then persists the new access token back to the database. [8] Make sure your zohoconnections record contains a valid refreshtoken and that the apidomain field is populated correctly. [8]
Step 2. Confirm the correct OAuth scopes are authorised.
For Zoho CRM report retrieval, your OAuth grant must include scopes such as ZohoCRM.coql.READ and ZohoCRM.org.ALL. For Zoho Desk, read access to tickets, contacts, and search requires scopes including Desk.tickets.READ, Desk.contacts.READ, and Desk.search.READ. [7] If any required scope is absent, the API call will fail silently or return an authorisation error — re-authorise the connection with the full scope list defined in your configuration. [7]
Step 3. Identify the correct app type and tool name.
When submitting a query, the system inspects the message and the apptype parameter (either "crm" or "desk") to decide which tool to invoke. For record-count style report queries, the tool resolved is getrecordcount. [2] For broader read operations, the planning layer iterates over a list of actions, calling executetoolwithrepair for each one with the tool name and its parameters. [6] Confirm that your apptype value matches the Zoho product you are querying, because the API client instantiated differs between CRM and Desk. [8]
Step 4. Execute the tool and capture the result.
The tool execution call passes your api instance, apptype, the resolved tool name, and a params dictionary (which should include a module key where relevant) to executetoolwithrepair. [6] The function returns an output object; extract the result via execout.get("result") and the final resolved tool name via execout.get("tool"). [2] If the tool returns a clarifyingquestion key instead of a result, the system pauses and surfaces that question to the user before proceeding. [6]
Step 5. Build direct links to the retrieved records.
Once a non-empty toolresult is available, pass it along with the tool name, params, apptype, data-centre code (dc), and any org/portal identifiers to buildzoholinks. [3] This function constructs deep-link URLs using the pattern https://crm.zoho.{dc}/crm/tab/{Module}/{RecordId} for CRM records and https://desk.zoho.{dc}/agent/{portal}/tickets/details/{TicketId} for Desk tickets. [3] The dc value defaults to "com" but must be set to your actual data centre (e.g., "eu", "au") if your account is hosted outside the US. [3]
Step 6. Review the full response payload.
The final response object returned to the caller includes sessionid, response (the human-readable answer), usage token counts, toolresult (the raw API data), and a links array containing name/URL pairs for each retrieved record. [4] In streaming mode, the same fields are emitted progressively, with status messages like "Calling Zoho tool: getrecordcount..." sent before the data arrives. [2] Save the links array if you need to present clickable "Open in Zoho" references alongside the report output. [1]
Common pitfalls
- Missing org ID for Zoho Desk. If
deskorgidis blank, the client attempts to auto-discover it by callinggetallorganizationsand persisting the first result. [8] If that discovery call also fails (e.g., due to a scope gap), subsequent Desk report calls will lack the required organisation context. - Wrong data-centre code. The
dcfield drives all URL construction. A mismatch (e.g., leaving it as"com"when your account is on"eu") produces valid-looking but unreachable deep links. [3] - Scope gaps causing silent failures. The OAuth scope list is long and product-specific. [7] A missing
READscope on the target module will not always surface as an obvious error — verify scopes before assuming the tool itself is broken. - Clarifying question interrupting the flow. If the tool execution returns a
clarifying_question, the pipeline halts and usage is tracked but no report data is returned. [6] Handle this state explicitly in your integration so the user is prompted rather than receiving an empty result.
What to check
- Verify that your stored connection record contains a non-expired
refreshtokenand the correctapidomainanddcvalues. [8] - Confirm that all required OAuth scopes — particularly
ZohoCRM.coql.READfor CRM orDesk.search.READfor Desk — are present in your authorised grant. [7] - After retrieval, inspect the
linksarray in the response to confirm that record URLs resolve to the expected module and data centre. [3]