Zoho CRM — Channel Overview
Researched: May 2026
Contents
- README.md — This file: overview, what to build, implementation plan
Full deferred-feature notes live at
docs/missing-incomplete-features/zoho-crm-channel.md.
Status
Deactivated — removed from the active channel catalogue April 2026. No provider package or import worker exists yet. Note: Zoho Books (accounting) has a separate OAuth callback already wired in channel-oauth.routes.ts; this doc is for Zoho CRM (lead management), which is a distinct product and OAuth app.
Why This Channel
Zoho CRM is widely used by Indian SMBs — Leadmetrics’ core target market. Connecting it transforms Leadmetrics from a content-generation tool into a closed-loop marketing platform: content drives traffic → traffic becomes leads → leads appear in Leadmetrics → agents can attribute which content converted. This is the “content ROI” story that justifies the subscription cost to budget-conscious clients.
Secondary value: agents get real lead context. The blog writer can know that the last 10 leads came in via the “local SEO tips” post and write more content in that vein.
Auth Mechanism
OAuth 2.0 (standard authorization code flow).
- Auth URL:
https://accounts.zoho.{region}/oauth/v2/auth(region:com/in/eu/au) - Token URL:
https://accounts.zoho.{region}/oauth/v2/token - Scopes:
ZohoCRM.modules.READ ZohoCRM.modules.WRITE ZohoCRM.users.READ - Token refresh: access token expires in 1 hour; refresh token is long-lived
The accounts-server query param returned in the callback determines which regional endpoint to use for all subsequent API calls — same pattern already implemented for Zoho Books in channel-oauth.routes.ts.
What It Enables
| Capability | Detail |
|---|---|
| Lead import | Sync Zoho Leads into Leadmetrics Lead + LeadContact tables on connect + nightly schedule |
| Contact sync | Optional: sync Zoho Contacts (warm leads / customers) |
| Deal pipeline read | Pull deal stages and amounts to measure revenue attribution |
| Lead source attribution | Tag which Leadmetrics content (blog, landing page, social) generated the lead |
| Two-way status sync | Update lead stage in Zoho when DM changes status in Leadmetrics (Phase 2) |
| Insight worker | Top lead sources; lead volume trend; conversion rate by content type |
Workers Needed
| Worker | Queue | Trigger |
|---|---|---|
zoho-lead-importer.worker.ts (new) | agent__zoho-lead-importer | On channel connect + nightly cron 0 1 * * * |
zoho-crm-insights.worker.ts (new) | agent__zoho-crm-insights | Weekly |
Insight Worker Output (ChannelInsight)
- Total leads this month vs last month
- Top 3 lead sources (which Leadmetrics content types convert)
- Lead-to-deal conversion rate over 30 days
- Average time from lead creation to first contact
- Suggested: content topics correlated with highest-converting leads
Implementation Plan
Phase 1 — Connect + Read-only Lead Import
-
Create
packages/providers/zoho/src/zoho-crm.ts:getAuthUrl(callbackUrl, channelId, region)— auth URL withaccess_type=offlineexchangeCode(code, callbackUrl, accountsServer)— returns tokens +accountsServerrefreshAccessToken(refreshToken, accountsServer)— region-aware token refreshgetLeads(accessToken, accountsServer, page?)—GET /crm/v7/Leadswith paginationgetContacts(accessToken, accountsServer, page?)—GET /crm/v7/Contactsverify()—GET /crm/v7/users?type=CurrentUser
-
Add OAuth routes to
apps/api/src/routers/channel-connect.ts:GET /zohoCrm/connect→ return auth URL (prompt region selection or default toin)GET /zohoCrm/callback→ exchange code (captureaccounts-server), store tokens +accountsServerinsubChannelInfo, close popup
-
Create
packages/agents/src/workers/zoho-lead-importer.worker.ts:- Load all tenants with an active Zoho CRM channel
- Fetch leads from Zoho (paginated, last-modified-since for incremental sync)
- Upsert into
Lead+LeadContacttables; setsource: "zoho_crm"+zohoLeadId - Record
lastSyncAton the channel
-
Re-activate seed entry in
packages/db/prisma/seed.ts -
Create
apps/dashboard/src/app/(dashboard)/channels/[id]/ZohoCrmChannelDetail.tsx:- Connection status + last sync time
- Total leads imported; leads this month
- Recent leads list (last 20)
- “Sync Now” button
Phase 2 — Two-way Sync + Deal Attribution
- Add
PATCH /crm/v7/Leads/:idto the provider: update lead stage from Leadmetrics - Zoho webhook endpoint:
POST /tenant/v1/zoho-crm/webhook— real-time lead push from Zoho - Lead source attribution: when a landing page form submits, capture
utm_source→ look up matchingSocialPostorBlogPost→ link toLead.sourceActivityId
DB Changes Needed
The existing Lead + LeadContact models (from the lead scoring pipeline) need two new fields:
// Add to Lead model:
zohoLeadId String? // Zoho record ID for two-way sync dedup
source String? // "zoho_crm" | "landing_page" | "manual"
// Add to ConnectedChannel subChannelInfo (JSON):
// { accountsServer: "https://accounts.zoho.in", ... }Seed Entry
// packages/db/prisma/seed.ts — CHANNEL_CATALOGUE
{
type: "ZohoCRM",
name: "Zoho CRM",
iconKey: "zoho",
description: "Import leads from Zoho CRM and measure content-to-lead attribution.",
authenticationType: "oauth2",
requiresUrl: false,
isActive: true, // change from false
categories: ["crm"],
},Related
docs/missing-incomplete-features/zoho-crm-channel.mddocs/missing-incomplete-features/lead-scoring-nurture.mddocs/missing-incomplete-features/twitter-zoho-channel-detail-pages.mdpackages/tools/src/zoho-books.ts— reference for Zoho API patterns (same OAuth infrastructure)