> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Zoho Desk as a data source

> Bring data from Zoho Desk to Nekt.

Zoho Desk is Zoho's customer service platform. Support teams use it to handle customer requests (tickets) arriving by email, phone, chat, social media and help center, together with the contacts and accounts behind them, the agents and teams who answer, and the activities around each request.

![](https://mintcdn.com/nekt/yi6g1gJqVfMryfQN/assets/logo/logo-zoho-desk.svg?fit=max\&auto=format\&n=yi6g1gJqVfMryfQN\&q=85\&s=132caf1a2212152f2a02b0e2663a19f8)

## Configuring Zoho Desk as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the Zoho Desk option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

There are two ways to connect your Zoho Desk account:

* **Sign in with Zoho** (recommended, United States data center only): you are taken to Zoho, sign in, and grant Nekt read access. If you belong to more than one Zoho Desk organization, Zoho asks which one to connect. Nothing else to fill in.
* **Use my own Zoho application**: you register an application in the Zoho API Console yourself and paste its credentials. Choose this if your company requires the connection to run under its own application, or if your account is hosted outside the United States (see the note below).

The following configurations are available:

* **Zoho data center** (default: United States): The data center hosting your Zoho Desk account. You can tell it from the address of your Zoho Desk: for example, `desk.zoho.com` is the United States data center and `desk.zoho.eu` is Europe. **Sign in with Zoho** works only with the United States data center (`zoho.com`); for any other data center, use your own Zoho application.
* **Organization ID** (optional): Only needed when your connection reaches more than one Zoho Desk organization (portal). You can find it in Zoho Desk under **Setup > Developer Space > API**. Leave it empty to use the only organization available.
* **Initial sync date** (required): Only records created or modified after this date are synced. Zoho Desk charges API credits for every request, so choose how much history you need: a recent date makes the first sync finish in fewer days (see API Limitations).
* **Include full thread content** (Advanced): (Default: `false`) Also fetch the full content (the email or message body) of every ticket thread. Without it, threads carry the summary Zoho shows in its lists. Each thread costs one extra Zoho API credit.
* **API credits to keep free** (Advanced, optional): Stop the sync when fewer than this many Zoho Desk API credits are left for the day, so your other Zoho integrations keep working. The next sync continues from where it stopped.

> [!NOTE]
>
> Sign in with a Zoho Desk user that can see every department you want to sync. If the user cannot read a module (for example, calls or events are not part of your Zoho Desk edition), the sync stops on its first run and tells you which streams to deselect.

> [!WARNING]
>
> **Sign in with Zoho** currently supports accounts hosted in the **United States** data center. If your Zoho Desk runs in another region, choose **Use my own Zoho application** and follow the steps below.

#### Using your own Zoho application

Only needed if you picked **Use my own Zoho application**. You will provide three values: Client ID, Client secret, and Refresh token. The process below takes a few minutes and is done only once.

**1. Create a Self Client**

Sign in to the [Zoho API Console](https://api-console.zoho.com/) with a Zoho Desk user that can see every department you want to sync. Click **GET STARTED**, choose **Self Client**, and click **CREATE NOW**.

A Self Client needs no name, homepage, or redirect URI. Open the **Client Secret** tab and copy the **Client ID** and **Client Secret**.

> [!NOTE]
>
> Use the API Console of your own data center. If your Zoho Desk runs on `desk.zoho.eu`, use `api-console.zoho.eu`, and so on.

**2. Generate an authorization code**

Open the **Generate Code** tab and fill in:

* **Scope**: paste the scopes below, separated by commas and with no spaces. All of them are read-only.

```
Desk.basic.READ,Desk.tickets.READ,Desk.search.READ,Desk.contacts.READ,Desk.accounts.READ,Desk.tasks.READ,Desk.calls.READ,Desk.events.READ,Desk.activities.READ,Desk.activities.tasks.READ,Desk.activities.calls.READ,Desk.activities.events.READ,Desk.products.READ,Desk.settings.READ,Desk.agents.READ
```

* **Scope Description**: any description, for example `Nekt data extraction`.
* **Time Duration**: choose 10 minutes, so you have time for the next step.

Click **CREATE**, select your Zoho Desk organization (portal) when prompted, and copy the generated code.

> [!WARNING]
>
> The code expires within the duration you selected. If it expires before you finish the next step, simply generate a new one.

**3. Exchange the code for a refresh token**

Run the request below, replacing the three placeholder values. Use the accounts URL of your data center: `accounts.zoho.com` for the United States, `accounts.zoho.eu` for Europe, `accounts.zohocloud.ca` for Canada, and so on.

```bash theme={null}
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=YOUR_GENERATED_CODE"
```

The response contains a `refresh_token`. Copy it: this is the third value Nekt needs.

> [!WARNING]
>
> The code can only be exchanged once. If you run the request twice, the second call returns `invalid_code` and you need to generate a new code.

**4. Paste the credentials into Nekt**

Fill in the Client ID, Client secret, and Refresh token fields, and select your data center.

> [!NOTE]
>
> The refresh token does not expire. It stays valid until you revoke it or delete the Self Client in the Zoho API Console, so you only go through this process once.

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

> Tip: The stream can be found more easily by typing its name.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: you can choose between INCREMENTAL and FULL\_TABLE.
  * Incremental: every time the extraction happens, we'll get only the new data, which is good if you want to keep every record ever fetched.
  * Full table: every time the extraction happens, we'll get the current state of the data, which is good if you don't want to have deleted data in your catalog.

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/runs/scheduling-and-triggers.md), consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times).

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

> [!WARNING]
>
> For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.

## API Limitations

Zoho Desk meters its API with a daily budget of **API credits** per organization, which depends on your edition and number of users (for example, 5,000 credits per day on the Free edition, 75,000 plus 500 per user on Professional, and 100,000 plus 1,000 per user on Enterprise). The connector keeps its cost low:

* Tickets, contacts, accounts, tasks, calls, events, and products cost about 3 credits per 100 records created or changed since the last run.
* Threads and comments cost about 3 credits per ticket that changed. **Include full thread content** adds 1 credit per thread.
* Time entries cost about 3 credits per agent for each month read, whatever the number of tickets: a daily sync is about 3 credits per agent, and a first sync of 12 months with 20 agents about 800 credits.
* Agents, departments, and teams cost a few credits per run.
* A sync that finds nothing new costs about **40 credits plus 3 per agent** with every stream selected. Syncing every hour therefore uses about 1,000 credits a day before any data is loaded; on small Zoho Desk plans (the Free edition has 5,000 credits a day), schedule the source **daily**.

The first sync reads the whole history and can need more credits than your organization has in a day (for example, about 60,000 credits for 20,000 tickets with threads and comments). In that case the history loads over several days:

* When the credits run out, the sync stops and keeps everything it already loaded. The next sync continues from the last point it fully loaded, so no record is skipped.
* Only the **very first** sync of the source can be marked as failed when the credits run out (Nekt cannot tell it apart from a Full sync, where a half-loaded table would replace the complete one). Every following sync finishes successfully, with a warning in the log, until the history is complete, including streams that are still waiting for their turn or were added later. Agents, departments, and teams are always read first, so they are complete before the credits run out.
* A **Full sync** or **Additional Full Sync** that runs out of credits is marked as failed, because it would replace your tables with partial ones. For large help desks, avoid scheduling Additional Full Syncs.
* If a sync cannot load anything at all (for example, the credits left for the day are already below **API credits to keep free**), it is marked as failed, so the problem shows up instead of the source silently standing still.
* If the credits run out before the same stream (for example, tickets) can make any progress in **3 syncs in a row**, the third sync is marked as failed and names the stream, so a table cannot stay behind without notice while the others update. Adding threads or comments to an existing source counts as progress for tickets and for the other ticket streams.
* A stream that is waiting while an earlier stream is still loading its history is not updated in that sync, and the run log says so every time (for example, "waiting for contacts; 3 syncs in a row"). If it waits **7 syncs in a row**, the sync is marked as failed and names both streams, so you can decide: ask Zoho for more API credits, use a more recent **Initial sync date**, or deselect the stream that is loading its history until the others catch up.

To load faster, set an **Initial sync date** (for example, the last 12 months), start with fewer streams, or ask Zoho for more API credits. Each run reports in its log how many credits it used.

If Zoho asks the connector to slow down for a short time, it waits and continues, so that run takes longer than usual.

# Streams and Fields

Fields that hold a structured value in Zoho Desk (such as the ticket's contact or assignee, or the custom fields under `cf`) are stored as a JSON string. You can read them in SQL with your warehouse's JSON functions. Field names are converted to lowercase with underscores (for example, `modifiedTime` becomes `modified_time`).

> **Tickets**
>
> Every ticket of the organization, with its status, assignment, contact and custom fields. Slug: `tickets`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the ticket |
> | `ticket_number` | String | Serial number of the ticket shown to agents and customers |
> | `subject` | String | Subject of the ticket |
> | `description` | String | Description of the ticket (HTML) |
> | `status` | String | Status of the ticket, including custom statuses |
> | `status_type` | String | Status type of the ticket: Open, On Hold or Closed |
> | `priority` | String | Priority of the ticket (for example High, Medium, Low) |
> | `channel` | String | Channel through which the ticket was created (Email, Phone, Web...) |
> | `category` | String | Category of the ticket |
> | `sub_category` | String | Subcategory of the ticket |
> | `classification` | String | Classification of the ticket (Problem, Request, Question...) |
> | `language` | String | Language of the ticket |
> | `resolution` | String | Resolution notes of the ticket |
> | `department_id` | String | ID of the department the ticket belongs to |
> | `department` | String | Department the ticket belongs to (id, name) (JSON string) |
> | `team_id` | String | ID of the team the ticket is assigned to |
> | `team` | String | Team the ticket is assigned to (id, name) (JSON string) |
> | `assignee_id` | String | ID of the agent the ticket is assigned to |
> | `assignee` | String | Agent the ticket is assigned to (JSON string) |
> | `contact_id` | String | ID of the contact who raised the ticket |
> | `contact` | String | Contact who raised the ticket, with their account (JSON string) |
> | `account_id` | String | ID of the account associated with the ticket |
> | `product_id` | String | ID of the product associated with the ticket |
> | `product` | String | Product associated with the ticket (JSON string) |
> | `email` | String | Email address recorded on the ticket |
> | `phone` | String | Phone number recorded on the ticket |
> | `due_date` | DateTime | Due date of the ticket |
> | `response_due_date` | DateTime | Due date of the first response |
> | `onhold_time` | DateTime | Time when the ticket was put on hold |
> | `closed_time` | DateTime | Time when the ticket was closed |
> | `customer_response_time` | DateTime | Time of the customer's latest response |
> | `created_time` | DateTime | Time when the ticket was created |
> | `created_by` | String | ID of the user who created the ticket |
> | `modified_time` | DateTime | Time when the ticket was last modified, used as the incremental replication key |
> | `modified_by` | String | ID of the user who last modified the ticket |
> | `is_over_due` | Boolean | Whether the ticket is past its due date |
> | `is_escalated` | Boolean | Whether the ticket is escalated |
> | `is_spam` | Boolean | Whether the ticket is marked as spam |
> | `is_read` | Boolean | Whether the agent has read the ticket |
> | `is_archived` | Boolean | Whether the ticket is archived |
> | `thread_count` | Integer | Number of threads (replies and messages) on the ticket |
> | `comment_count` | Integer | Number of comments on the ticket |
> | `shared_departments` | String | Departments the ticket is shared with and their access (JSON string) |
> | `secondary_contacts` | String | Secondary contacts of the ticket (JSON string) |
> | `last_thread` | String | Summary of the latest thread (channel, direction, draft) (JSON string) |
> | `entity_skills` | String | Skills associated with the ticket (JSON string) |
> | `child_ticket_count` | Integer | Number of child tickets of the ticket |
> | `parent_ticket` | String | Parent ticket, when this ticket is a child ticket (JSON string) |
> | `source_ticket` | String | Ticket this ticket was created from (JSON string) |
> | `relationship_type` | String | Relationship of the ticket with its parent ticket |
> | `sla_id` | String | ID of the SLA applied to the ticket |
> | `locked_time` | DateTime | Time when the ticket was locked |
> | `custom_fields` | String | Custom fields of the ticket as returned under customFields (JSON string) |
> | `layout_id` | String | ID of the layout of the ticket |
> | `web_url` | String | URL of the ticket in Zoho Desk |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |

> **Ticket Threads**
>
> Messages exchanged on each ticket (emails, chats, social and forum replies), incoming and outgoing. Slug: `ticket_threads`. Sync: Incremental, using `ticket_modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the thread |
> | `ticket_id` | String | ID of the ticket the thread belongs to |
> | `ticket_modified_time` | DateTime | Modification time of the ticket when its threads were read, used as the incremental replication key |
> | `channel` | String | Channel of the thread (EMAIL, FORUMS, CHAT, FEEDBACK...) |
> | `direction` | String | Whether the thread is incoming (in) or outgoing (out) |
> | `status` | String | Delivery status of the thread (SUCCESS, PENDING, FAILED, DRAFT) |
> | `visibility` | String | Visibility of the thread (public or private) |
> | `is_description_thread` | Boolean | Whether the thread is the ticket's description |
> | `is_forward` | Boolean | Whether the thread was sent as a forward |
> | `can_reply` | Boolean | Whether replies can be added to the thread |
> | `has_attach` | Boolean | Whether the thread has attachments |
> | `attachment_count` | Integer | Number of attachments on the thread |
> | `content_type` | String | Format of the thread content (text/html or text/plain) |
> | `summary` | String | Summary (beginning) of the thread content, as listed by Zoho |
> | `content` | String | Full content of the thread; filled only when 'Include full thread content' is on |
> | `plain_text` | String | Full content of the thread as plain text; filled only when 'Include full thread content' is on |
> | `from_email_address` | String | Email address the thread was sent from |
> | `to` | String | Recipients of the thread (email channel) |
> | `cc` | String | Addresses copied on the thread (email channel) |
> | `bcc` | String | Addresses blind-copied on the thread (email channel) |
> | `phoneno` | String | Phone number the thread came from (telephony channels) |
> | `responder_id` | String | ID of the agent who responded |
> | `responded_in` | String | Time the agent took to respond (HH:MM:SS) |
> | `sentiment` | String | Tone of the customer in the thread |
> | `created_time` | DateTime | Time when the thread was created |
> | `author` | String | Author of the thread (name, email, type AGENT or END\_USER) (JSON string) |
> | `source` | String | Source of the thread in its channel (JSON string) |
> | `channel_related_info` | String | Channel-specific information of the thread (JSON string) |
> | `last_rating_icon_url` | String | Icon of the latest customer rating of the thread |

> **Ticket Comments**
>
> Comments added to each ticket by agents, public or private. Slug: `ticket_comments`. Sync: Incremental, using `ticket_modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the comment |
> | `ticket_id` | String | ID of the ticket the comment belongs to |
> | `ticket_modified_time` | DateTime | Modification time of the ticket when its comments were read, used as the incremental replication key |
> | `content` | String | Content of the comment |
> | `content_type` | String | Format of the comment content (html or plainText) |
> | `is_public` | Boolean | Whether the comment is visible to the customer |
> | `commenter_id` | String | ID of the user who added the comment |
> | `commenter` | String | User who added the comment (name, email, role, type) (JSON string) |
> | `commented_time` | DateTime | Time when the comment was added |
> | `modified_time` | DateTime | Time when the comment was last modified |
> | `attachments` | String | Files attached to the comment (JSON string) |
> | `mention` | String | Agents and teams mentioned in the comment (JSON string) |

> **Ticket Time Entries**
>
> Time logged by agents on tickets, with billing information. Read per agent, so a new or edited entry is loaded even when its ticket did not change. Slug: `ticket_time_entries`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the time entry |
> | `ticket_id` | String | ID of the ticket the time entry belongs to |
> | `executed_time` | DateTime | Time when the work of the time entry started |
> | `hours_spent` | Integer | Hours in the time entry |
> | `minutes_spent` | Integer | Minutes in the time entry |
> | `seconds_spent` | Integer | Seconds in the time entry |
> | `description` | String | Description of the time entry |
> | `request_charge_type` | String | Type of request (Customer Service, Upgrade Request...) |
> | `is_billable` | Boolean | Whether the time entry is billable |
> | `billing_type` | String | Billing type configured in time tracking |
> | `mode` | String | How the time was recorded (MANUAL or AUTO) |
> | `agent_cost_per_hour` | Number | Cost per hour of the agent |
> | `additional_cost` | Number | Additional cost incurred |
> | `fixed_cost` | Number | Fixed cost of the time entry |
> | `total_cost` | Number | Total cost of the time entry |
> | `invoice_id` | String | ID of the invoice the time entry was billed in |
> | `owner_id` | String | ID of the agent who owns the time entry |
> | `owner` | String | Agent who owns the time entry (JSON string) |
> | `creator_id` | String | ID of the user who created the time entry |
> | `created_by` | String | User who created the time entry |
> | `created_time` | DateTime | Time when the time entry was created |
> | `modified_by` | String | User who last modified the time entry |
> | `modified_time` | DateTime | Time when the time entry was last modified (its creation time when Zoho does not send one), used as the incremental replication key |
> | `department_id` | String | ID of the department of the time entry |
> | `parent` | String | Record the time entry is logged against (type, id, ticket number) (JSON string) |
> | `is_trashed` | Boolean | Whether the time entry is in the trash |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |

> **Contacts**
>
> The customers who raise tickets. Slug: `contacts`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the contact |
> | `first_name` | String | First name of the contact |
> | `last_name` | String | Last name of the contact |
> | `email` | String | Primary email address of the contact |
> | `secondary_email` | String | Secondary email address of the contact |
> | `phone` | String | Phone number of the contact |
> | `mobile` | String | Mobile number of the contact |
> | `title` | String | Job title of the contact |
> | `type` | String | Type of the contact |
> | `description` | String | Description of the contact |
> | `street` | String | Street of the contact's address |
> | `city` | String | City of the contact's address |
> | `state` | String | State of the contact's address |
> | `zip` | String | Postal code of the contact's address |
> | `country` | String | Country of the contact's address |
> | `facebook` | String | Facebook handle of the contact |
> | `twitter` | String | Twitter handle of the contact |
> | `language` | String | Language of the contact |
> | `time_zone` | String | Time zone of the contact |
> | `account_id` | String | ID of the account the contact belongs to |
> | `account` | String | Account the contact belongs to (id, name, website) (JSON string) |
> | `owner_id` | String | ID of the agent who owns the contact |
> | `owner` | String | Agent who owns the contact (JSON string) |
> | `is_end_user` | Boolean | Whether the contact is a help center end user |
> | `is_spam` | Boolean | Whether the contact is marked as spam |
> | `is_anonymous` | Boolean | Whether the contact is anonymous |
> | `is_deleted` | Boolean | Whether the contact has been deleted |
> | `is_trashed` | Boolean | Whether the contact is in the trash |
> | `photo_url` | String | URL of the contact's photo |
> | `web_url` | String | URL of the contact in Zoho Desk |
> | `layout_id` | String | ID of the layout of the contact |
> | `zoho_crm_contact` | String | Linked Zoho CRM contact or lead (id, type) (JSON string) |
> | `customer_happiness` | String | Share of good, okay and bad ratings from the contact (JSON string) |
> | `created_time` | DateTime | Time when the contact was created |
> | `modified_time` | DateTime | Time when the contact was last modified, used as the incremental replication key |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |

> **Accounts**
>
> The customer organizations contacts belong to. Slug: `accounts`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the account |
> | `account_name` | String | Name of the account |
> | `email` | String | Email address of the account |
> | `phone` | String | Phone number of the account |
> | `fax` | String | Fax number of the account |
> | `website` | String | Website of the account |
> | `industry` | String | Industry of the account |
> | `code` | String | Code of the account |
> | `annualrevenue` | String | Annual revenue of the account, as entered in Zoho Desk |
> | `description` | String | Description of the account |
> | `street` | String | Street of the account's address |
> | `city` | String | City of the account's address |
> | `state` | String | State of the account's address |
> | `zip` | String | Postal code of the account's address |
> | `country` | String | Country of the account's address |
> | `owner_id` | String | ID of the agent who owns the account |
> | `owner` | String | Agent who owns the account (JSON string) |
> | `is_deleted` | Boolean | Whether the account has been deleted |
> | `is_trashed` | Boolean | Whether the account is in the trash |
> | `web_url` | String | URL of the account in Zoho Desk |
> | `layout_id` | String | ID of the layout of the account |
> | `zoho_crm_account` | String | Linked Zoho CRM account (id) (JSON string) |
> | `customer_happiness` | String | Share of good, okay and bad ratings from the account (JSON string) |
> | `created_time` | DateTime | Time when the account was created |
> | `modified_time` | DateTime | Time when the account was last modified, used as the incremental replication key |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |

> **Tasks**
>
> Tasks assigned to agents, related or not to a ticket. Slug: `tasks`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the task |
> | `subject` | String | Subject of the task |
> | `description` | String | Description of the task |
> | `status` | String | Status of the task |
> | `priority` | String | Priority of the task |
> | `department_id` | String | ID of the department of the task |
> | `department` | String | Department of the task (id, name) (JSON string) |
> | `owner_id` | String | ID of the agent who owns the task |
> | `assignee` | String | Agent assigned to the task (JSON string) |
> | `creator_id` | String | ID of the user who created the task |
> | `ticket_id` | String | ID of the ticket the task is related to |
> | `ticket` | String | Ticket the task is related to (number, subject, contact) (JSON string) |
> | `contact_id` | String | ID of the contact the task is related to |
> | `contact` | String | Contact the task is related to (JSON string) |
> | `team_id` | String | ID of the team the task is assigned to |
> | `team` | String | Team the task is assigned to (JSON string) |
> | `completed_time` | DateTime | Time when the task was completed |
> | `created_time` | DateTime | Time when the task was created |
> | `modified_time` | DateTime | Time when the task was last modified, used as the incremental replication key |
> | `is_trashed` | Boolean | Whether the task is in the trash |
> | `layout_id` | String | ID of the layout of the task |
> | `web_url` | String | URL of the task in Zoho Desk |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |
> | `category` | String | Category of the task |
> | `due_date` | DateTime | Due date of the task |
> | `start_time` | DateTime | Start time of the task |
> | `is_commented` | Boolean | Whether the task has comments |
> | `is_spam` | Boolean | Whether the task is marked as spam |
> | `reminder` | String | Reminder settings of the task (JSON string) |

> **Calls**
>
> Support calls logged in Zoho Desk. Slug: `calls`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the call |
> | `subject` | String | Subject of the call |
> | `description` | String | Description of the call |
> | `status` | String | Status of the call |
> | `priority` | String | Priority of the call |
> | `department_id` | String | ID of the department of the call |
> | `department` | String | Department of the call (id, name) (JSON string) |
> | `owner_id` | String | ID of the agent who owns the call |
> | `assignee` | String | Agent assigned to the call (JSON string) |
> | `creator_id` | String | ID of the user who created the call |
> | `ticket_id` | String | ID of the ticket the call is related to |
> | `ticket` | String | Ticket the call is related to (number, subject, contact) (JSON string) |
> | `contact_id` | String | ID of the contact the call is related to |
> | `contact` | String | Contact the call is related to (JSON string) |
> | `team_id` | String | ID of the team the call is assigned to |
> | `team` | String | Team the call is assigned to (JSON string) |
> | `completed_time` | DateTime | Time when the call was completed |
> | `created_time` | DateTime | Time when the call was created |
> | `modified_time` | DateTime | Time when the call was last modified, used as the incremental replication key |
> | `is_trashed` | Boolean | Whether the call is in the trash |
> | `layout_id` | String | ID of the layout of the call |
> | `web_url` | String | URL of the call in Zoho Desk |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |
> | `direction` | String | Direction of the call (inbound or outbound) |
> | `duration` | Integer | Duration of the call, in seconds |
> | `start_time` | DateTime | Start time of the call |

> **Events**
>
> Meetings and other scheduled activities. Slug: `events`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the event |
> | `subject` | String | Subject of the event |
> | `description` | String | Description of the event |
> | `status` | String | Status of the event |
> | `priority` | String | Priority of the event |
> | `department_id` | String | ID of the department of the event |
> | `department` | String | Department of the event (id, name) (JSON string) |
> | `owner_id` | String | ID of the agent who owns the event |
> | `assignee` | String | Agent assigned to the event (JSON string) |
> | `creator_id` | String | ID of the user who created the event |
> | `ticket_id` | String | ID of the ticket the event is related to |
> | `ticket` | String | Ticket the event is related to (number, subject, contact) (JSON string) |
> | `contact_id` | String | ID of the contact the event is related to |
> | `contact` | String | Contact the event is related to (JSON string) |
> | `team_id` | String | ID of the team the event is assigned to |
> | `team` | String | Team the event is assigned to (JSON string) |
> | `completed_time` | DateTime | Time when the event was completed |
> | `created_time` | DateTime | Time when the event was created |
> | `modified_time` | DateTime | Time when the event was last modified, used as the incremental replication key |
> | `is_trashed` | Boolean | Whether the event is in the trash |
> | `layout_id` | String | ID of the layout of the event |
> | `web_url` | String | URL of the event in Zoho Desk |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |
> | `category` | String | Category of the event (for example Meeting) |
> | `duration` | Integer | Duration of the event, in minutes |
> | `start_time` | DateTime | Start time of the event |
> | `custom_fields` | String | Custom fields of the event as returned under customFields (JSON string) |

> **Products**
>
> Products and services associated with tickets, contacts and accounts. Slug: `products`. Sync: Incremental, using `modified_time` as the replication key. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the product |
> | `product_name` | String | Name of the product |
> | `product_code` | String | Code of the product |
> | `description` | String | Description of the product |
> | `unit_price` | Number | Unit price of the product |
> | `department_ids` | List of strings | IDs of the departments the product is associated with |
> | `owner_id` | String | ID of the agent who owns the product |
> | `created_by` | String | ID of the user who created the product |
> | `created_time` | DateTime | Time when the product was created |
> | `modified_by` | String | ID of the user who last modified the product |
> | `modified_time` | DateTime | Time when the product was last modified, used as the incremental replication key |
> | `is_deleted` | Boolean | Whether the product has been deleted |
> | `layout_id` | String | ID of the layout of the product |
> | `cf` | String | Custom fields of the record, keyed by the field's API name (for example cf\_region) (JSON string) |

> **Agents**
>
> Help desk users, in every status (active, disabled, imported and deleted). Slug: `agents`. Sync: Full table: the whole list is read on every run. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the agent |
> | `name` | String | Full name of the agent |
> | `first_name` | String | First name of the agent |
> | `last_name` | String | Last name of the agent |
> | `email_id` | String | Email address of the agent |
> | `phone` | String | Phone number of the agent |
> | `mobile` | String | Mobile number of the agent |
> | `extn` | String | Phone extension of the agent |
> | `status` | String | Activation status of the agent (ACTIVE, DISABLED, DELETED, IMPORTED) |
> | `role_id` | String | ID of the agent's role |
> | `profile_id` | String | ID of the agent's profile |
> | `role_permission_type` | String | Permission type of the agent's role (Admin, Light...) |
> | `is_confirmed` | Boolean | Whether the agent confirmed their invitation |
> | `is_zia_agent` | Boolean | Whether the agent is the Zia bot |
> | `lang_code` | String | Language of the agent |
> | `country_code` | String | Locale of the agent |
> | `time_zone` | String | Time zone of the agent |
> | `zuid` | String | Zoho user ID of the agent |
> | `about_info` | String | About text of the agent |
> | `photo_url` | String | URL of the agent's photo |
> | `associated_department_ids` | List of strings | IDs of the departments the agent belongs to |
> | `associated_chat_department_ids` | List of strings | IDs of the departments where the agent handles chats |
> | `channel_expert` | List of strings | Channels the agent is an expert in |
> | `cf` | String | Custom fields of the agent, keyed by the field's API name (JSON string) |

> **Departments**
>
> Departments of the help desk. Slug: `departments`. Sync: Full table: the whole list is read on every run. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the department |
> | `name` | String | Name of the department |
> | `name_in_customer_portal` | String | Name of the department shown in the help center |
> | `description` | String | Description of the department |
> | `is_default` | Boolean | Whether this is the default department |
> | `is_enabled` | Boolean | Whether the department is enabled |
> | `is_visible_in_customer_portal` | Boolean | Whether the department appears in the help center |
> | `is_assign_to_team_enabled` | Boolean | Whether tickets can be assigned to teams |
> | `has_logo` | Boolean | Whether the department has a logo |
> | `chat_status` | String | Chat availability of the department |
> | `creator_id` | String | ID of the user who created the department |
> | `created_time` | DateTime | Time when the department was created |
> | `sanitized_name` | String | URL-friendly version of the department name used by Zoho |

> **Teams**
>
> Teams of agents in each department. Slug: `teams`. Sync: Full table: the whole list is read on every run. Primary key: `id`.
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `id` | String | Unique identifier of the team |
> | `name` | String | Name of the team |
> | `description` | String | Description of the team |
> | `department_id` | String | ID of the department the team belongs to |
> | `logo_url` | String | URL of the team's logo |
> | `agents` | String | Agents who are members of the team (JSON string) |
> | `derived_agents` | String | Agents who are members through roles or sub-teams (JSON string) |
> | `roles` | String | Roles whose agents are members of the team (JSON string) |
> | `roles_with_subordinates` | String | Roles whose agents and subordinates are members (JSON string) |
> | `sub_teams` | String | Teams nested in this team (JSON string) |

## Implementation Notes

### How incremental sync works

* **Changed records only**: tickets, contacts, accounts, tasks, calls, events, and products are read in the order Zoho last changed them, starting where the previous run stopped. Records changed in the last 15 minutes are picked up by the next run, because Zoho takes a few minutes to make a change searchable.
* **Threads and comments** are read for each ticket that changed since the last run. If you add one of these streams to an existing source, its first run reads every ticket since the **Initial sync date**, while the other streams keep their progress.
* **Time entries** are read by their own modification time, agent by agent and one month at a time, so a new or edited entry is loaded even when its ticket did not change.
* Each sync re-reads the last few minutes before where the previous one stopped, in case Zoho made a change searchable later than usual. Those records are merged, not duplicated.
* **Deleted records** are not removed from your tables by incremental syncs. Use a Full sync to rebuild a table without them.

### Limitations to be aware of

* Archived tickets are not included.
* Time entries of agents deleted or deactivated in Zoho Desk cannot be read once Zoho stops serving them. Entries loaded before that stay in your table, and the run log says how many agents were affected.
* Whether adding a comment counts as a change to the ticket is not documented by Zoho. If it does not, a new comment is loaded the next time its ticket changes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.