Beam Help
Get help now

How-to · Zoho DESK

How to list ticket time entries in Zoho Desk

Retrieve all time entries logged on a ticket.

Listing all time entries logged against a Zoho Desk ticket is straightforward once you know the correct API endpoint and the required OAuth scopes. This article walks you through the full process — from authentication to interpreting the response.


Why this matters


Time entries capture how long agents spend working on a ticket, and surfacing them programmatically lets you build billing reports, audit agent effort, or feed data into external payroll and invoicing tools. If you are integrating Zoho Desk with a third-party system, or simply want to pull time-tracking data in bulk, this endpoint is your starting point. Note that Beam Help is independent expert support for Zoho — we are not official Zoho support.


Step-by-step


Step 1. Confirm your OAuth scopes include ticket permissions.


Before making any API call, verify that your connected OAuth client has been granted the necessary Desk scopes. At minimum you need Desk.tickets.READ in your scope string; a broader configuration also includes Desk.tickets.ALL alongside scopes for contacts, tasks, and other modules. [2]


Step 2. Identify the ticket ID you want to query.


Every time-entry request is scoped to a single ticket. Locate the numeric or alphanumeric ticketId for the ticket in question — you can find it in the Zoho Desk URL when viewing the ticket, or retrieve it programmatically via the tickets list endpoint. [3]


Step 3. Send a GET request to the time entries endpoint.


Issue an HTTP GET to the following path, substituting your actual ticket identifier:


GET /api/v1/tickets/{ticketId}/timeEntries

In Python, using a pre-configured client wrapper, the call looks like this:


def list_ticket_time_entries(self, ticketId: str, p: dict = None):
    return self.c.request("GET", f"/api/v1/tickets/{ticketId}/timeEntries", p, None)

The optional p parameter accepts a dictionary of query-string parameters (for example, pagination or filtering options). [3]


Step 4. (Optional) Filter results by billing type.


If you only need entries grouped or filtered by their billing classification, use the dedicated billing-type sub-resource instead:


GET /api/v1/tickets/{ticketId}/timeEntries/billingType

This returns time entries organised by their billing category rather than a flat list. [6]


Step 5. (Optional) Retrieve a rolled-up summary instead of individual entries.


When you need aggregate totals — such as total billable hours for a ticket — call the summary endpoint:


GET /api/v1/tickets/{ticketId}/timeEntries/summary

This gives you a summation of all time logged against the ticket without returning each individual record. [7]


Step 6. Handle pagination with the p parameter.


Both the main list endpoint and the billing-type endpoint accept a p dictionary for query parameters. Pass pagination keys (such as from and limit) inside this dictionary to page through large result sets. [3][6]


Step 7. Create or update entries if needed.


Once you can read entries, you may also want to write them. To log a new entry, send a POST to the same base path with a data payload:


POST /api/v1/tickets/{ticketId}/timeEntries

To modify an existing entry, use a PATCH request that also includes the timeEntryId:


PATCH /api/v1/tickets/{ticketId}/timeEntries/{timeEntryId}

[8][4]


Common pitfalls


  • Missing or insufficient scopes. If your token was generated without Desk.tickets.READ (or Desk.tickets.ALL), the API will return an authorisation error. Re-generate your OAuth token with the correct scope string before retrying. [2]
  • Wrong ticket ID format. Passing a ticket *number* (the human-readable reference shown in the UI) instead of the internal ticket *ID* will result in a 404 or empty response. Always use the internal identifier. [3]
  • Confusing the list endpoint with the summary endpoint. The /timeEntries path returns individual records; /timeEntries/summary returns aggregated totals. Calling the wrong one will give you data in an unexpected shape. [3][7]

What to check


  • Confirm your OAuth access token includes Desk.tickets.READ or Desk.tickets.ALL in its granted scopes before making the request. [2]
  • Verify the ticketId in your request path is the internal Zoho Desk record ID, not the display ticket number. [3]
  • If you expect multiple pages of results, ensure you are passing appropriate pagination parameters inside the p dictionary so no entries are silently omitted. [3][6]

Sources cited

  1. [1] server.py: build_zoho_links
  2. [2] config.py
  3. [3] GET /api/v1/tickets/{ticketId}/timeEntries
  4. [4] PATCH /api/v1/tickets/{ticketId}/timeEntries/{timeEntryId}
  5. [5] server.py: chat_stream
  6. [6] GET /api/v1/tickets/{ticketId}/timeEntries/billingType
  7. [7] GET /api/v1/tickets/{ticketId}/timeEntries/summary
  8. [8] POST /api/v1/tickets/{ticketId}/timeEntries
List Ticket Time Entries in Zoho Desk | Beam Help