# Zoho CRM

## Prerequisites

* A Zoho CRM account (Free, Standard/Starter, Professional, Enterprise/Zoho One, or Ultimate/CRM Plus).
* An Omnata Sync Engine installation

***

## Authentication

The plugin supports two OAuth connection methods.

### OAuth (Server based)

Uses Zoho's standard Authorization Code flow managed via a Snowflake Security Integration.

```sql
select 'https://'||get(parse_json(SYSTEM$allowlist()),0):"host"::varchar||'/oauth/complete-secret' as REDIRECT_URL;
```

To determine the Authorized Redirect URI for your Snowflake account, run the following Snowflake query:

Log in to <https://api-console.zoho.com.au/> to create a Server-based Application.

You will provide the following values to the Omnata connection flow:

| Prompt              | Value                                   |
| ------------------- | --------------------------------------- |
| OAuth Client ID     | From your Zoho API Console application. |
| OAuth Client Secret | From your Zoho API Console application. |
| Domain              | `accounts.<your-region>`                |

The subdomain is always `accounts.` with the value for your region (e.g. `zoho.com` for USA).

Later in the connection steps, you will also need to provide:

| Field                           | Description                                                               |
| ------------------------------- | ------------------------------------------------------------------------- |
| **Data Center**                 | The Zoho data center region your organisation is in (see table below).    |
| **Product Edition**             | Your Zoho CRM subscription tier — used to calculate the API credit quota. |
| **Purchased Users Count**       | Number of licensed users — used to calculate the API credit quota.        |
| **Addon API credits purchased** | Additional API credits purchased separately (enter `0` if none).          |

### OAuth (Self client)

Intended for server-to-server integrations where a browser-based redirect is not practical.

Log in to <https://api-console.zoho.com.au/> to create a Self Client Application.

When you create the Self client, you need to add comma separated scopes:

{% code overflow="wrap" %}

```
ZohoCRM.bulk.ALL,ZohoCRM.settings.modules.READ,ZohoCRM.settings.fields.READ,ZohoCRM.org.READ,ZohoFiles.files.ALL,ZohoCRM.modules.ALL
```

{% endcode %}

In the Omnata connection form you need to provide:

| Field                           | Description                                                                                                         |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **Client ID**                   | From your Zoho API Console self-client application.                                                                 |
| **Client Secret**               | From your Zoho API Console self-client application.                                                                 |
| **Initial Code**                | The one-time code generated in Zoho API Console. This is exchanged for a long-lived refresh token on first connect. |
| **Data Center**                 | Your Zoho data center region.                                                                                       |
| **Product Edition**             | Your Zoho CRM subscription tier.                                                                                    |
| **Purchased Users Count**       | Number of licensed users.                                                                                           |
| **Addon API credits purchased** | Additional API credits purchased separately.                                                                        |

#### **Data Center Region Reference**

| Label     | API Domain            |
| --------- | --------------------- |
| USA       | `www.zohoapis.com`    |
| Australia | `www.zohoapis.com.au` |
| Europe    | `www.zohoapis.eu`     |
| India     | `www.zohoapis.in`     |
| China     | `www.zohoapis.com.cn` |
| Japan     | `www.zohoapis.jp`     |

***

### Inbound Syncs

Syncs Zoho CRM module records into Snowflake tables.

Records are extracted using the [Zoho CRM Bulk Read API](https://www.zoho.com/crm/developer/docs/api/v5/bulk-read/overview.html) and fetch incrementally wherever possible.

#### Supported strategies

| Strategy         | Behaviour                                                                           |
| ---------------- | ----------------------------------------------------------------------------------- |
| **Full Refresh** | Re-reads all records every run.                                                     |
| **Incremental**  | Only reads records modified since the last successful sync (using `Modified_Time`). |

#### Configuration

There are no additional configuration fields for inbound syncs.\
Select the modules (streams) you want to sync during the stream selection step. Schemas are fetched dynamically from the Zoho field definitions.

#### Available streams

Each Zoho CRM module becomes an individual stream in Omnata (e.g. `Leads`, `Contacts`, `Accounts`, `Deals`, `Tasks`, etc.).

The following modules are excluded because they do not support the Bulk Read API or produce errors during field discovery:

`Home`, `Workqueue`, `Meetings`, `Reports`, `Dashboards`, `PurchaseOrders`, `SalesInbox`, `Feeds`, `PriceBooks`, `Documents`, `Visits`, `Social`, `Email Analytics`, `Email Template Analytics`, `Actions Performed`, `EmailSentiment`, `SalesOrders`, `QuotedItems`, `OrderedItems`, `PurchaseItems`, `InvoicedItems`, `Forecast Quotas`, `Forecast Items`, `Forecast Groups`, `LockingInformation`, `EmailTemplate`, `EmailDrafts`, `CalendarBookings`, `Unknown`.

***

### Outbound Syncs

Syncs a Snowflake table to a Zoho CRM module.

Records are uploaded using the [Zoho CRM Bulk Write API](https://www.zoho.com/crm/developer/docs/api/v5/bulk-write/overview.html).

#### Supported strategies

| Strategy   | Behaviour                                                                 |
| ---------- | ------------------------------------------------------------------------- |
| **Create** | Inserts new records only.                                                 |
| **Update** | Updates existing records, matched by a unique field.                      |
| **Upsert** | Inserts new records and updates existing ones, matched by a unique field. |

#### Configuration

1. **Module** — select the Zoho CRM module to write to (e.g. Leads, Contacts, Accounts). The list is fetched dynamically from your Zoho organisation.
2. **Unique Field** *(Update / Upsert only)* — select the field used to match existing records (e.g. `Email`, `Account_Name`).
3. **Field Mappings** — map Snowflake columns to Zoho CRM fields. Mandatory Zoho fields are highlighted.

#### Supported modules

The following modules are supported for outbound syncing:

* Accounts
* Attachments
* Calls
* Campaigns
* Cases
* Contacts
* DealHistory
* Deals
* Emails
* Forecasts
* Invoices
* Leads
* Notes
* Products
* Quotes
* Solutions
* Tasks
* Vendors

***

### Rate Limits

Zoho CRM enforces API credit–based rate limits. The plugin automatically calculates and respects these limits based on the **Product Edition**, **Purchased Users Count**, and **Addon API credits** provided at connection time.

| Edition               | Base credits | Per-user credits |
| --------------------- | ------------ | ---------------- |
| Free                  | 5,000        | —                |
| Standard / Starter    | 50,000       | 250              |
| Professional          | 50,000       | 500              |
| Enterprise / Zoho One | 50,000       | 1,000            |
| Ultimate / CRM Plus   | 50,000       | 2,000            |

Add-on credits purchased separately are added to the total.

The plugin enforces per-day request budgets for bulk write jobs, bulk read jobs, and standard record API calls, derived from the credit totals above. See [Zoho's API Limits documentation](https://www.zoho.com/crm/developer/docs/api/v5/api-limits.html) for full details.

***

### Troubleshooting

| Symptom                             | Likely cause                                              | Resolution                                                                 |
| ----------------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------- |
| Connection fails with an auth error | Initial code expired (Self client)                        | Generate a new one-time code in Zoho API Console.                          |
| Field list returns HTTP 204         | Rate limit hit on the fields API                          | Retry after a short wait; the plugin will retry automatically.             |
| Import / export job times out       | Zoho job took longer than 5 minutes                       | Re-run the sync; large modules may require multiple runs.                  |
| Module not visible in stream list   | Module is on the excluded list or has no bulk API support | This is a Zoho limitation; use the standard records API for these modules. |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.omnata.com/omnata-product-documentation/omnata-sync-for-snowflake/apps/zoho-crm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
