

# Connecting to Zoho CRM
<a name="connecting-to-data-zoho-crm"></a>

Zoho CRM acts as a single repository to bring sales, marketing, and customer support activities together, and streamline process, policy, and people in one platform. Zoho CRM can be easily customized to meet the specific needs of any business type and size.

Zoho CRM's developer platform offers the right mix of low-code and pro-code tools for businesses/enterprises to automate work, integrate data across enterprise stack, and create custom solutions for web and mobile.

**Topics**
+ [AWS Glue support for Zoho CRM](zoho-crm-support.md)
+ [Policies containing the API operations for creating and using connections](zoho-crm-configuring-iam-permissions.md)
+ [Configuring Zoho CRM](zoho-crm-configuring.md)
+ [Configuring Zoho CRM connections](zoho-crm-configuring-connections.md)
+ [Reading from Zoho CRM entities](zoho-crm-reading-from-entities.md)
+ [Zoho CRM connection options](zoho-crm-connection-options.md)
+ [Limitations and notes for Zoho CRM connector](zoho-crm-connector-limitations.md)

# AWS Glue support for Zoho CRM
<a name="zoho-crm-support"></a>

AWS Glue supports Zoho CRM as follows:

**Supported as a source?**  
Yes – Sync and Async. You can use AWS Glue ETL jobs to query data from Zoho CRM.

**Supported as a target?**  
No.

**Supported Zoho CRM API versions**  
The following Zoho CRM API versions are supported:
+ v7

# Policies containing the API operations for creating and using connections
<a name="zoho-crm-configuring-iam-permissions"></a>

The following sample policy describes the required AWS IAM permissions for creating and using connections. If you are creating a new role, create a policy that contains the following:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:ListConnectionTypes",
        "glue:DescribeConnectionType",
        "glue:RefreshOAuth2Tokens",
        "glue:ListEntities",
        "glue:DescribeEntity"
      ],
      "Resource": "*"
    }
  ]
}
```

------

If you don't want to use the above method, alternatively use the following managed IAM policies:
+ [AWSGlueServiceRole](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole) – Grants access to resources that various AWS Glue processes require to run on your behalf. These resources include AWS Glue, Amazon S3, IAM, CloudWatch Logs, and Amazon EC2. If you follow the naming convention for resources specified in this policy, AWS Glue processes have the required permissions. This policy is typically attached to roles specified when defining crawlers, jobs, and development endpoints.
+ [AWSGlueConsoleFullAccess](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSGlueConsoleFullAccess) – Grants full access to AWS Glue resources when an identity that the policy is attached to uses the AWS Management Console. If you follow the naming convention for resources specified in this policy, users have full console capabilities. This policy is typically attached to users of the AWS Glue console.

# Configuring Zoho CRM
<a name="zoho-crm-configuring"></a>

Before you can use AWS Glue to transfer data from Zoho CRM, you must meet these requirements:

## Minimum requirements
<a name="zoho-crm-configuring-min-requirements"></a>

The following are minimum requirements:
+ You have a Zoho CRM account.
+ Your Zoho CRM account is enabled for API access.
+ You have a registered API client under the API Console to obtain OAuth Credentials.

# Configuring Zoho CRM connections
<a name="zoho-crm-configuring-connections"></a>

The grant type determines how AWS Glue communicates with Zoho CRM to request access to your data. Your choice affects the requirements that you must meet before you create the connection. Zoho CRM supports only the AUTHORIZATION\$1CODE grant type for OAuth 2.0.
+ This grant type is considered "three-legged" OAuth as it relies on redirecting users to a third-party authorization server to authenticate the user. It is used when creating connections via the AWS Glue console. The AWS Glue console will redirect the user to Zoho CRM where the user must login and allow Glue the requested permissions to access their Zoho CRM instance.
+ Users may still opt to create their own connected app in Zoho CRM and provide their own client ID, Auth URL, Token URL, and Instance URL when creating connections through the AWS Glue console. In this scenario, they will still be redirected to Zoho CRM to login and authorize AWS Glue to access their resources.
+ This grant type results in a refresh token and access token. The access token will remain valid for one hour, and may be refreshed automatically without user interaction using the refresh token.
+ For public Zoho CRM documentation on creating a connected app for Authorization Code OAuth flow, see [Authentication](https://www.zoho.com/crm/developer/docs/api/v7/oauth-overview.html).

To configure a Zoho CRM connection:

1. In AWS Glue Glue Studio, create a connection under **Data Connections** by following the steps below:

   1. When selecting a **Connection type**, select Zoho CRM.

   1. Provide the `INSTANCE_URL` of the Zoho CRM instance you want to connect to.

   1. Provide the user client application client ID.

   1. Select the appropriate **Auth URL** from the dropdown.

   1. Select the appropriate **Token URL** from the dropdown.

   1. Select the AWS IAM role which AWS Glue can assume and has permissions for following actions:

------
#### [ JSON ]

****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "secretsmanager:DescribeSecret",
              "secretsmanager:GetSecretValue",
              "secretsmanager:PutSecretValue",
              "ec2:CreateNetworkInterface",
              "ec2:DescribeNetworkInterfaces",
              "ec2:DeleteNetworkInterface"
            ],
            "Resource": "*"
          }
        ]
      }
      ```

------

   1. Select the `secretName` which you want to use for this connection in AWS Glue to put the tokens.

   1. Select the network options if you want to use your network.

1. Grant the IAM role associated with your AWS Glue job permission to read `secretName`.

1. In your AWS Glue job configuration, provide `connectionName` as an **Additional network connection**.

# Reading from Zoho CRM entities
<a name="zoho-crm-reading-from-entities"></a>

**Prerequisite**

Zoho CRM objects you would like to read from. You will need the object name.

**Supported entities for Sync source**:


| Entity | Can be filtered | Supports limit | Supports Order by | Supports Select \$1 | Supports partitioning | 
| --- | --- | --- | --- | --- | --- | 
| Product | Yes | Yes | Yes | Yes | Yes | 
| Quote | Yes | Yes | Yes | Yes | Yes | 
| Purchase Order | Yes | Yes | Yes | Yes | Yes | 
| Solution | Yes | Yes | Yes | Yes | Yes | 
| Call | Yes | Yes | Yes | Yes | Yes | 
| Task | Yes | Yes | Yes | Yes | Yes | 
| Event | Yes | Yes | Yes | Yes | Yes | 
| Invoice | Yes | Yes | Yes | Yes | Yes | 
| Account | Yes | Yes | Yes | Yes | Yes | 
| Contact | Yes | Yes | Yes | Yes | Yes | 
| Vendor | Yes | Yes | Yes | Yes | Yes | 
| Campaign | Yes | Yes | Yes | Yes | Yes | 
| Deal | Yes | Yes | Yes | Yes | Yes | 
| Lead | Yes | Yes | Yes | Yes | Yes | 
| Custom Module | Yes | Yes | Yes | Yes | Yes | 
| Sales Order | Yes | Yes | Yes | Yes | Yes | 
| Price Books | Yes | Yes | Yes | Yes | Yes | 
| Case | Yes | Yes | Yes | Yes | Yes | 

**Example**:

```
zoho_read = glueContext.create_dynamic_frame.from_options(
    connection_type="ZOHO",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "API_VERSION": "v7",
        "INSTANCE_URL": "https://www.zohoapis.in/"
    }
```

**Supported entities for Async source**:


| Entity | Can be filtered | Supports limit | Supports Order by | Supports Select \$1 | Supports partitioning | 
| --- | --- | --- | --- | --- | --- | 
| Product | Yes | No | No | Yes | No | 
| Quote | Yes | No | No | Yes | No | 
| Purchase Order | Yes | No | No | Yes | No | 
| Solution | Yes | No | No | Yes | No | 
| Call | Yes | No | No | Yes | No | 
| Task | Yes | No | No | Yes | No | 
| Event | Yes | No | No | Yes | No | 
| Invoice | Yes | No | No | Yes | No | 
| Account | Yes | No | No | Yes | No | 
| Contact | Yes | No | No | Yes | No | 
| Vendor | Yes | No | No | Yes | No | 
| Campaign | Yes | No | No | Yes | No | 
| Deal | Yes | No | No | Yes | No | 
| Lead | Yes | No | No | Yes | No | 
| Custom Module | Yes | No | No | Yes | No | 
| Sales Order | Yes | No | No | Yes | No | 
| Price Books | Yes | No | No | Yes | No | 
| Case | Yes | No | No | Yes | No | 

**Example**:

```
zoho_read = glueContext.create_dynamic_frame.from_options(
    connection_type="ZOHO",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "API_VERSION": "v7",
        "INSTANCE_URL": "https://www.zohoapis.in/",
        "TRANSFER_MODE": "ASYNC"
    }
```

**Zoho CRM field details**:

Zoho CRM provides endpoints to fetch metadata dynamically for supported entities. Therefore, operator support is captured at the datatype level.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/glue/latest/dg/zoho-crm-reading-from-entities.html)

## Partitioning queries
<a name="zoho-crm-reading-partitioning-queries"></a>

Partitioning is not supported in Async mode.

**Filter-based partitioning (Sync mode)**:

You can provide the additional Spark options `PARTITION_FIELD`, `LOWER_BOUND`, `UPPER_BOUND`, and `NUM_PARTITIONS` if you want to utilize concurrency in Spark. With these parameters, the original query would be split into `NUM_PARTITIONS` number of sub-queries that can be executed by Spark tasks concurrently.
+ `PARTITION_FIELD`: the name of the field to be used to partition the query.
+ `LOWER_BOUND`: an **inclusive** lower bound value of the chosen partition field.

  For the Datetime field, we accept the Spark timestamp format used in Spark SQL queries.

  Examples of valid value:

  ```
  "2024-09-30T01:01:01.000Z"
  ```
+ `UPPER_BOUND`: an **exclusive** upper bound value of the chosen partition field.
+ `NUM_PARTITIONS`: the number of partitions.

Example:

```
zoho_read = glueContext.create_dynamic_frame.from_options(
    connection_type="zohocrm",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "API_VERSION": "v7",
        "PARTITION_FIELD": "Created_Time"
        "LOWER_BOUND": "2022-01-01T01:01:01.000Z"
        "UPPER_BOUND": "2024-01-01T01:01:01.000Z"
        "NUM_PARTITIONS": "10"
    }
```

# Zoho CRM connection options
<a name="zoho-crm-connection-options"></a>

The following are connection options for Zoho CRM:
+ `ENTITY_NAME`(String) - (Required) Used for Read. The name of your object in Zoho CRM.
+ `API_VERSION`(String) - (Required) Used for Read. Zoho CRM Rest API version you want to use.
+ `SELECTED_FIELDS`(List<String>) - Default: empty(SELECT \$1). Used for Read. Columns you want to select for the object.
+ `FILTER_PREDICATE`(String) - Default: empty. Used for Read. It should be in the Spark SQL format.
+ `QUERY`(String) - Default: empty. Used for Read. Full Spark SQL query.
+ `PARTITION_FIELD`(String) - Used for Read. Field to be used to partition query.
+ `LOWER_BOUND`(String)- Used for Read. An inclusive lower bound value of the chosen partition field.
+ `UPPER_BOUND`(String) - Used for Read. An exclusive upper bound value of the chosen partition field.
+ `NUM_PARTITIONS`(Integer) - Default: 1. Used for Read. Number of partitions for read.
+ `INSTANCE_URL`(String) - (Required) Used for Read. A valid Zoho CRM instance URL.
+ `TRANSFER_MODE`(String) - Used to indicate whether the query should be run on Async mode.

# Limitations and notes for Zoho CRM connector
<a name="zoho-crm-connector-limitations"></a>

The following are limitations or notes for the Zoho CRM connector:
+ With API version v7, you can fetch a maximum of 100,000 records. See the [Zoho documentation](https://www.zoho.com/crm/developer/docs/api/v7/get-records.html) .
+ For the Event entity, the label "Meeting" is displayed as mentioned in the [Zoho documentation](https://www.zoho.com/crm/developer/docs/api/v7/modules-api.html).
+ For Select All functionality:
  + You can fetch a maximum of 50 fields from SaaS for both the GET and POST call.
  + If you want to have data for some specific field that does not belong in the first 50 fields, you will need to manually provide the list of selected fields.
  + If more than 50 fields are selected, any fields beyond the 50 fields will be trimmed and will contain null data in Amazon S3. 
  + In case of a filter expression, if the user-provided list of 50 fields does not include "id" and "Created\$1Time," a custom exception will be raised to prompt the user to include these fields.
+ Filter operators may vary from field-to-field despite of having the same data type. Therefore, you must manually specify a different operator for any field that triggers an error in the SaaS platform. 
+ For Sort By functionality:
  + Data can only be sorted by a single field without a filter expression, whereas data can be sorted by multiple fields when a filter expression is applied.
  + If no sort order is specified for the selected field, the data will be retrieved in ascending order by default. 
+ The supported regions for the Zoho CRM connector are US, Europe, India, Australia and Japan.
+ Async read functionality [Limitations:](https://www.zoho.com/crm/developer/docs/api/v7/bulk-read/limitations.html)
  + Limit order by and partitioning is not supported in the Async mode. 
  + In the Async mode we can transfer data up to 500 pages with 200,000 records per page.
  + For a one-minute interval, only 10 requests are allowed for download. When you exceed the download limit, the system returns an HTTP 429 error and pauses all download requests for one minute before processing can resume.
  + After completing the bulk job, you can access the downloadable file only for a period of one day. After that, you cannot access the file via endpoints.
  + A maximum of 200 select fields can be given via an endpoint. If you specify more than 200 select fields in an endpoint, the system will automatically export all available fields for that module.
  + External fields created in any module are not supported in Bulk Read APIs.
  + Sorting and `Group_by` clauses are not supported via this API endpoint.
  + The values of the fields with sensitive health data will be retrieved only when the **Restrict Data access through API** option in the compliance settings is **disabled**. If the option is enabled, the value will be **empty** in the result.
  + Filtration/Criteria Limits
    + The maximum number of criteria that can be used in a query is 25.
    + Filtration/Criteria on multiline text fields is not supported.