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

# Zoho CRM Integration

> Export leads to Zoho CRM

## Overview

Finscreener provides **Zoho-ready lead data** that you can push to your own Zoho CRM. We act as a **DATA PROVIDER** - formatting and serving data while you handle your own Zoho connection.

```
Finscreener API  →  Your System  →  Your Zoho CRM
(Data Provider)     (Fetch leads)    (Push leads)
```

<Info>
  Your system fetches leads from Finscreener API, then pushes them to your Zoho CRM using your own credentials.
</Info>

## CRM API Endpoints

All endpoints require **Developer API authentication** (API key login).

| Endpoint                     | Method | Description                        |
| ---------------------------- | ------ | ---------------------------------- |
| `/api/crm/orders`            | GET    | List orders (for CRM export)       |
| `/api/crm/orders/{id}/leads` | GET    | Get Zoho-ready leads from order    |
| `/api/crm/newlead`           | POST   | Get any entity as Zoho lead format |

### List CRM Orders

```bash theme={null}
GET /api/crm/orders
Authorization: Bearer <token>
Query Params: page=1, limit=10
```

**Response:**

```json theme={null}
{
  "orders": [
    {
      "_id": "order_xxx",
      "orderName": "My Order",
      "paymentOption": "credits",
      "created_at": "2026-01-03T16:45:17",
      "total_amount": 25.0,
      "status": "completed",
      "payment_status": "paid",
      "items_count": 25
    }
  ],
  "total": 4,
  "page": 1,
  "limit": 10,
  "pages": 1
}
```

### Get Order Leads

```bash theme={null}
GET /api/crm/orders/{order_id}/leads
Authorization: Bearer <token>
```

**Response (Zoho-Ready Format):**

```json theme={null}
{
  "order_id": "order_xxx",
  "order_name": "My Order",
  "payment_status": "paid",
  "status": "completed",
  "leads": [
    {
      "type": "company",
      "identifier": "U12345MH2024PTC123456",
      "name": "ABC Pvt Ltd",
      "lead": {
        "Last_Name": "ABC Pvt Ltd",
        "Company": "ABC Pvt Ltd",
        "Email": "contact@abc.com",
        "Phone": "9876543210",
        "City": "Mumbai",
        "State": "Maharashtra",
        "Lead_Source": "Finscreener",
        "CIN": "U12345MH2024PTC123456"
      }
    }
  ],
  "total": 25
}
```

### Get Entity as Lead

<Warning>
  This endpoint requires an **active subscription** with access to recently registered data:

  * `gst` → Requires **Recent\_GST** feature
</Warning>

```bash theme={null}
POST /api/crm/newlead
Authorization: Bearer <token>
Content-Type: application/json

{
  "entity_type": "gst",
  "identifier": "27AABCU9603R1ZM"
}
```

## Zoho Lead Field Mapping

| Finscreener Field  | Zoho Lead Field                        |
| ------------------ | -------------------------------------- |
| Company Name       | Last\_Name, Company                    |
| Email              | Email                                  |
| Phone              | Phone, Mobile                          |
| Address Line       | Street                                 |
| City               | City                                   |
| State              | State                                  |
| Pincode            | Zip\_Code                              |
| Country            | Country                                |
| Source             | Lead\_Source (always "Finscreener")    |
| CIN                | CIN (custom field)                     |
| DIN                | DIN (custom field)                     |
| GSTIN              | GSTIN (custom field)                   |
| Incorporation Date | Date\_of\_Incorporation (custom field) |
| Company Type       | Company\_Type (custom field)           |
| Paid Up Capital    | Paid\_Up\_Capital (custom field)       |
| Industry           | Industry (custom field)                |

## Zoho CRM Setup Guide

### Step 1: Create Zoho OAuth Client

1. Go to [api-console.zoho.com](https://api-console.zoho.com/)
2. Click **Add Client**
3. Choose **Server-based Applications**
4. Fill details:
   * Client Name: `Finscreener Integration`
   * Homepage URL: `http://localhost`
   * Authorized Redirect URI: `http://localhost`
5. Click **Create**
6. Save your **CLIENT\_ID** and **CLIENT\_SECRET**

### Step 2: Generate Grant Token (One Time)

Open this URL in browser (for India DC):

```
https://accounts.zohocorp.in/oauth/v2/auth?
scope=ZohoCRM.modules.ALL
&client_id=YOUR_CLIENT_ID
&response_type=code
&access_type=offline
&redirect_uri=http://localhost
```

<Warning>
  `access_type=offline` is mandatory to get refresh token. The grant code is valid for **3 minutes only**!
</Warning>

**Zoho Data Centers:**

| Region | OAuth URL                | API Base                                          |
| ------ | ------------------------ | ------------------------------------------------- |
| India  | accounts.zohocorp.in     | [www.zohoapis.in](http://www.zohoapis.in)         |
| US     | accounts.zohocorp.com    | [www.zohoapis.com](http://www.zohoapis.com)       |
| EU     | accounts.zohocorp.eu     | [www.zohoapis.eu](http://www.zohoapis.eu)         |
| AU     | accounts.zohocorp.com.au | [www.zohoapis.com.au](http://www.zohoapis.com.au) |

### Step 3: Exchange Grant Token for Access + Refresh Token

```bash theme={null}
curl -X POST https://accounts.zohocorp.in/oauth/v2/token \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=http://localhost" \
  -d "code=GRANT_TOKEN"
```

**Response:**

```json theme={null}
{
  "access_token": "1000.xxxxx",
  "refresh_token": "1000.yyyyy",
  "expires_in": 3600,
  "token_type": "Bearer"
}
```

Save securely: `refresh_token` (long-lived) and `access_token` (expires in \~1 hour)

### Step 4: Refresh Access Token

Access tokens expire. Use refresh token to get new ones:

```python theme={null}
import requests

def get_zoho_access_token(refresh_token, client_id, client_secret):
    url = "https://accounts.zohocorp.in/oauth/v2/token"
    payload = {
        "refresh_token": refresh_token,
        "client_id": client_id,
        "client_secret": client_secret,
        "grant_type": "refresh_token",
    }
    r = requests.post(url, data=payload, timeout=30)
    r.raise_for_status()
    return r.json()["access_token"]
```

### Step 5: Push Leads to Zoho CRM

```python theme={null}
import requests

def create_zoho_lead(access_token, lead_data):
    url = "https://www.zohoapis.in/crm/v2/Leads"
    headers = {
        "Authorization": f"Zoho-oauthtoken {access_token}",
        "Content-Type": "application/json",
    }
    payload = {"data": [lead_data]}
    r = requests.post(url, headers=headers, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()

# Example: Push lead from Finscreener
finscreener_lead = {
    "Last_Name": "ABC Pvt Ltd",
    "Company": "ABC Pvt Ltd",
    "Email": "contact@abc.com",
    "Phone": "9876543210",
    "City": "Mumbai",
    "State": "Maharashtra",
    "Lead_Source": "Finscreener",
}

result = create_zoho_lead(access_token, finscreener_lead)
```

## Integration Flow

```
1. User creates/pays for order on Finscreener
              ↓
2. Fetch Zoho-ready leads via /api/crm/orders/{id}/leads
              ↓
3. Push leads to your Zoho CRM (using your credentials)
```

## Daily Sync Script

Example Python script for daily Zoho lead sync (run via cron):

```python theme={null}
#!/usr/bin/env python3
"""
Daily Zoho Lead Sync Script
Run via cron: 0 9 * * * /usr/bin/python3 /path/to/sync_leads.py
"""
import requests

# Finscreener API
FINSCREENER_API = "https://api.finscreener.in"
FINSCREENER_API_KEY = "fsk_your_api_key"

# Zoho Config
ZOHO_CLIENT_ID = "your_client_id"
ZOHO_CLIENT_SECRET = "your_client_secret"
ZOHO_REFRESH_TOKEN = "your_refresh_token"
ZOHO_API_BASE = "https://www.zohoapis.in"

def get_finscreener_token():
    r = requests.post(f"{FINSCREENER_API}/api/auth/login",
                      json={"api_key": FINSCREENER_API_KEY})
    return r.json()["token"]["access_token"]

def get_zoho_token():
    r = requests.post("https://accounts.zohocorp.in/oauth/v2/token", data={
        "refresh_token": ZOHO_REFRESH_TOKEN,
        "client_id": ZOHO_CLIENT_ID,
        "client_secret": ZOHO_CLIENT_SECRET,
        "grant_type": "refresh_token",
    })
    return r.json()["access_token"]

def fetch_order_leads(fs_token, order_id):
    r = requests.get(
        f"{FINSCREENER_API}/api/crm/orders/{order_id}/leads",
        headers={"Authorization": f"Bearer {fs_token}"}
    )
    return r.json()

def push_to_zoho(zoho_token, leads):
    url = f"{ZOHO_API_BASE}/crm/v2/Leads"
    headers = {
        "Authorization": f"Zoho-oauthtoken {zoho_token}",
        "Content-Type": "application/json",
    }
    zoho_leads = [{
        "Last_Name": l["lead"].get("Last_Name", "NA"),
        "Company": l["lead"].get("Company"),
        "Email": l["lead"].get("Email"),
        "Phone": l["lead"].get("Phone"),
        "City": l["lead"].get("City"),
        "State": l["lead"].get("State"),
        "Lead_Source": "Finscreener",
    } for l in leads]
    r = requests.post(url, headers=headers, json={"data": zoho_leads})
    return r.json()

def main():
    fs_token = get_finscreener_token()
    zoho_token = get_zoho_token()

    r = requests.get(f"{FINSCREENER_API}/api/crm/orders",
                     headers={"Authorization": f"Bearer {fs_token}"})
    for order in r.json()["orders"]:
        if order["payment_status"] == "paid":
            leads = fetch_order_leads(fs_token, order["_id"])
            if leads.get("leads"):
                push_to_zoho(zoho_token, leads["leads"])
                print(f"Synced {len(leads['leads'])} leads")

if __name__ == "__main__":
    main()
```

## Common Mistakes to Avoid

| Mistake                                        | Solution                               |
| ---------------------------------------------- | -------------------------------------- |
| Forgetting `access_type=offline` in Zoho OAuth | Always include it to get refresh token |
| Using wrong Zoho DC (.com vs .in)              | Match your Zoho account region         |
| Hardcoding access token                        | Use refresh token to auto-generate     |
| Not handling 401 errors                        | Refresh token and retry                |
| Creating duplicate leads                       | Search by Email before creating        |
