Listing all attachments on a Zoho Desk ticket is straightforward once you know the correct API endpoint and have the right OAuth scopes in place. This article walks you through the exact call and supporting setup — from Beam Help, your independent expert support for Zoho (not official Zoho support).
Why this matters
When building integrations, automations, or audit workflows, you often need to programmatically retrieve every file attached to a support ticket. Whether you're syncing attachments to an external document store, validating that required files were uploaded, or simply displaying them in a custom portal, knowing how to call the list-attachments endpoint correctly saves significant debugging time.
Step-by-step
Step 1. Confirm your OAuth scopes.
Before making any API call, ensure your connected application has been granted the necessary ticket-level permissions. At minimum, your OAuth token must include Desk.tickets.READ — and ideally Desk.tickets.ALL — to retrieve ticket data including attachments. [8]
Step 2. Identify the ticket ID.
You need the unique ticketId (or ticket_id) for the ticket whose attachments you want to list. This is the internal Zoho Desk identifier, not the human-readable ticket number shown in the UI. You can obtain it from a prior ticket search or creation response. [2]
Step 3. Send a GET request to the attachments endpoint.
Issue an HTTP GET to the following path, substituting your actual ticket identifier:
GET /api/v1/tickets/{ticketId}/attachments
This operation — referred to as listticketattachments — returns the collection of files associated with that ticket. [2] An equivalent operation named list_attachments uses the same HTTP method and path structure, confirming this is the canonical route. [3]
In Python, using a pre-configured client wrapper, the call looks like this:
def list_ticket_attachments(self, ticketId: str, p: dict = None):
return self.c.request("GET", f"/api/v1/tickets/{ticketId}/attachments", p, None)
The optional p parameter can carry query-string arguments such as pagination controls. [2]
Step 4. Handle pagination if needed.
The endpoint accepts a p parameter for pagination. If a ticket has many attachments, pass appropriate page or offset values in that dictionary to retrieve subsequent pages of results. [^2, ^3]
Step 5. Drill into a single attachment (optional).
If you need the full metadata for one specific file after listing them, use the single-attachment endpoint by appending the attachmentId to the path:
GET /api/v1/tickets/{ticketId}/attachments/{attachmentId}
This getticketattachment operation returns detailed information about that individual file. [5]
Step 6. Retrieve attachments on a transition draft (advanced, optional).
If your workflow uses ticket transitions and you need attachments scoped to a specific transition draft rather than the ticket itself, a separate endpoint exists:
GET /api/v1/tickets/{ticketId}/transitions/{transitionId}/attachments
This is a distinct operation and should only be used when you specifically need transition-level attachment data. [7]
Common pitfalls
- Missing or insufficient OAuth scope. If your token only carries
Desk.tickets.WRITEorDesk.tickets.CREATEbut notDesk.tickets.READorDesk.tickets.ALL, the API will reject the request. Always verify the full scope list in your OAuth configuration. [8]
- Confusing ticket number with ticket ID. The
ticketIdin the URL path is the system-generated internal identifier. Using the display ticket number (e.g., "TKT-1042") will result in a 404 or invalid-record error. Retrieve the correct ID from a prior API response.
- Forgetting to add attachments before listing. If you're testing and the list returns empty, confirm that files have actually been uploaded. Attachments are added via a
POSTto the same/api/v1/tickets/{ticketId}/attachmentspath. [^4, ^6]
- Transition attachments vs. ticket attachments. The transition-draft endpoint (
/transitions/{transitionId}/attachments) is not interchangeable with the main ticket attachments endpoint. Calling the wrong one will return an empty or unrelated result set. [7]
What to check
- Scope verification: Confirm that
Desk.tickets.READorDesk.tickets.ALLappears in your active OAuth token's scope list before making the call. [8] - Correct ticket ID: Validate that the
ticketIdyou're passing is the internal system ID returned by the Zoho Desk API, not the human-readable reference number shown in the support portal. [2] - Response completeness: If you expect multiple attachments but only see a partial list, check whether pagination parameters need to be supplied via the
pargument to retrieve all pages. [3]