Skip to main content
Z

Zoho CRM Integration

Connect your AI agents to Zoho CRM

One-Click Connect available! Zoho CRM connects via OAuth. Just click “Connect Platform”, select your region, and authorize. No API keys, tokens, or manual configuration needed.

Step 1: Connect Zoho CRM

Recommended: Use the one-click OAuth connection. It automatically handles authentication, token refresh, and multi-region support.

  1. 1Go to Settings Integrations
  2. 2Click Connect Platform Zoho CRM
  3. 3Select your Zoho region (US, EU, India, Australia, or Japan)
  4. 4Log in to your Zoho account and click Accept to authorize
  5. 5Done! Your access token refreshes automatically. No maintenance needed
DetailValue
Base URLSet automatically from your Zoho region
Auth TypeOAuth 2.0 (automatic)
Token RefreshAutomatic (every 60 minutes)
API Versionv7

Supported Regions

RegionDomainAPI Base URL
United States (default)zoho.comhttps://www.zohoapis.com
Europezoho.euhttps://www.zohoapis.eu
Indiazoho.inhttps://www.zohoapis.in
Australiazoho.com.auhttps://www.zohoapis.com.au
Japanzoho.jphttps://www.zohoapis.jp

Step 2: Add Actions with Pre-Built Templates

Once connected, click Add Action to open the template picker. Choose from 60 pre-built actions across 15 Zoho CRM modules, so there is no need to configure endpoints, body templates, or field names manually.

New: Pre-built templates configure everything for you in one click. Just select a template, review the settings, and save. You can always customize the action after adding it.

Available Templates (60 total)

Contacts

GETSearch Contact
POSTCreate Contact
PUTUpdate Contact
DELETEDelete Contact

Leads

GETSearch Lead
POSTCreate Lead
PUTUpdate Lead
DELETEDelete Lead

Accounts

GETSearch Account
POSTCreate Account
PUTUpdate Account
DELETEDelete Account

Deals

GETSearch Deal
POSTCreate Deal
PUTUpdate Deal
DELETEDelete Deal

Cases

GETSearch Case
POSTCreate Case
PUTUpdate Case
DELETEDelete Case

Tasks

GETSearch Task
POSTCreate Task
PUTUpdate Task
DELETEDelete Task

Calls

GETSearch Call
POSTLog Call
PUTUpdate Call
DELETEDelete Call

Events

GETSearch Event
POSTSchedule Event
PUTUpdate Event
DELETEDelete Event

Notes

GETSearch Notes
POSTCreate Note
PUTUpdate Note
DELETEDelete Note

Products

GETSearch Products
POSTCreate Product
PUTUpdate Product
DELETEDelete Product

Quotes

GETSearch Quotes
POSTCreate Quote
PUTUpdate Quote
DELETEDelete Quote

Appointments

GETSearch Appointments
POSTSchedule Appointment
PUTUpdate Appointment
DELETECancel Appointment

Solutions

GETSearch Solutions
POSTCreate Solution

Direct Lookups

GETGet Contact by ID
GETGet Lead by ID
GETGet Account by ID
GETGet Deal by ID
GETGet Case by ID

Users & Tags

GETList Users
GETGet User
GETList Tags
POSTAdd Tag
POSTRemove Tag

What Each Action Does

GET

Search

Searches across all text fields in the module using the /search?word= API. Requires at least 2 characters. Returns up to 200 matching records.

GET /crm/v7/Contacts/search?word=John

# Response (200 OK):
{
  "data": [{
    "id": "4878934000000123456",
    "First_Name": "John",
    "Last_Name": "Smith",
    "Email": "[email protected]",
    "Phone": "+15551234567"
  }],
  "info": { "count": 1, "more_records": false }
}

# No results returns 204 No Content (empty body, not an error)
POST

Create

Creates a new record. All Zoho create operations use the {"data": [{...}]} array wrapper, even for a single record. Returns 201 on success.

POST /crm/v7/Contacts
Body: { "data": [{ "Last_Name": "Smith", "Email": "[email protected]" }] }

# Response (201 Created):
{
  "data": [{
    "code": "SUCCESS",
    "status": "success",
    "message": "record added",
    "details": {
      "id": "4878934000000314001",
      "Created_Time": "2026-02-12T10:00:00-08:00"
    }
  }]
}
PUT

Update

Updates an existing record. Zoho uses PUT (not PATCH), but it behaves like a partial update where only provided fields are changed. Returns 200 on success.

PUT /crm/v7/Contacts/4878934000000123456
Body: { "data": [{ "Email": "[email protected]" }] }

# Response (200 OK):
{
  "data": [{
    "code": "SUCCESS",
    "status": "success",
    "message": "record updated",
    "details": { "id": "4878934000000123456" }
  }]
}
DELETE

Delete

Soft-deletes a record. Deleted records go to the Recycle Bin for 60 days and can be restored. After 60 days they are permanently removed.

DELETE /crm/v7/Contacts/4878934000000123456

# Response (200 OK):
{
  "data": [{
    "code": "SUCCESS",
    "status": "success",
    "message": "record deleted",
    "details": { "id": "4878934000000123456" }
  }]
}
GETPOSTPUTDELETE

Notes

Notes are attached to a parent record (Contact, Lead, Deal, etc.). When creating a note, you must specify the parent module and record ID. Search retrieves notes across all parent records.

# Search Notes
GET /crm/v7/Notes/search?word=follow up

# Create Note (attached to a Contact)
POST /crm/v7/Notes
Body: { "data": [{ "Note_Title": "Call follow-up", "Note_Content": "Discussed pricing options.", "Parent_Id": { "id": "4878934000000123456" }, "se_module": "Contacts" }] }

# Update Note
PUT /crm/v7/Notes/{{note_id}}
Body: { "data": [{ "Note_Title": "Updated title", "Note_Content": "Updated content" }] }

# 200 OK
{
  "data": [{ "code": "SUCCESS", "status": "success", "message": "record updated" }]
}

# Delete Note
DELETE /crm/v7/Notes/4878934000000567890
GETPOSTPUTDELETE

Products

Products represent your catalog items. They can be linked to Quotes and Deals as line items. Only Product_Name is required for creation.

# Search Products
GET /crm/v7/Products/search?word=Widget

# Create Product
POST /crm/v7/Products
Body: { "data": [{ "Product_Name": "Widget Pro", "Unit_Price": 49.99, "Product_Code": "WP-001", "Qty_in_Stock": 500 }] }

# Update Product
PUT /crm/v7/Products/4878934000000234567
Body: { "data": [{ "Unit_Price": 59.99 }] }

# Delete Product
DELETE /crm/v7/Products/4878934000000234567
GETPOSTPUTDELETE

Quotes

Quotes represent price proposals sent to prospects. They contain line items (Quoted_Items) referencing Products. A Subject is required.

# Search Quotes
GET /crm/v7/Quotes/search?word=Enterprise

# Create Quote
POST /crm/v7/Quotes
Body: { "data": [{ "Subject": "Enterprise Plan - Acme Corp", "Quoted_Items": [{ "product": { "id": "4878934000000234567" }, "quantity": 10, "list_price": 49.99 }] }] }

# Update Quote
PUT /crm/v7/Quotes/4878934000000345678
Body: { "data": [{ "Subject": "Enterprise Plan v2 - Acme Corp" }] }

# Delete Quote
DELETE /crm/v7/Quotes/4878934000000345678
GETPOSTPUTDELETE

Appointments

Appointments are scheduled meetings or visits. They require a name, start time, and end time in ISO 8601 format. Cancel uses the DELETE method and moves the appointment to the Recycle Bin.

# Search Appointments
GET /crm/v7/Appointments/search?word=demo

# Schedule Appointment
POST /crm/v7/Appointments
Body: { "data": [{ "Appointment_Name": "Product Demo - Acme Corp", "Start_DateTime": "2026-02-15T14:00:00-08:00", "End_DateTime": "2026-02-15T15:00:00-08:00", "Location": "Zoom" }] }

# Update Appointment
PUT /crm/v7/Appointments/4878934000000456789
Body: { "data": [{ "Start_DateTime": "2026-02-16T14:00:00-08:00", "End_DateTime": "2026-02-16T15:00:00-08:00" }] }

# Cancel Appointment
DELETE /crm/v7/Appointments/4878934000000456789
GETPOST

Solutions

Solutions are knowledge base articles linked to Cases. They help your AI agent reference known fixes during support calls. Only Solution_Title is required.

# Search Solutions
GET /crm/v7/Solutions/search?word=password reset

# Create Solution
POST /crm/v7/Solutions
Body: { "data": [{ "Solution_Title": "How to Reset Password", "Solution_Details": "Navigate to Settings > Security > Change Password. Enter current password, then new password twice." }] }
GET

Direct Lookups

Fetch a single record by its Zoho ID. Use these when you already have the record ID from a previous action (e.g. after a search). Returns the full record with all fields.

# Get Contact by ID
GET /crm/v7/Contacts/4878934000000123456

# Get Lead by ID
GET /crm/v7/Leads/4878934000000123456

# Get Account by ID
GET /crm/v7/Accounts/4878934000000123456

# Get Deal by ID
GET /crm/v7/Deals/4878934000000123456

# Get Case by ID
GET /crm/v7/Cases/4878934000000123456

# Response (200 OK):
{
  "data": [{
    "id": "4878934000000123456",
    "Full_Name": "John Smith",
    "Email": "[email protected]",
    ...all fields
  }]
}
GETPOST

Users & Tags

Manage CRM users and record tags. List Users retrieves your team members (useful for assigning records). Tags help categorize records. Add Tag and Remove Tag use the record actions endpoint.

# List Users
GET /crm/v7/users?type=AllUsers

# Get User by ID
GET /crm/v7/users/4878934000000123456

# List Tags for a module
GET /crm/v7/settings/tags?module=Contacts

# Add Tag to a record
POST /crm/v7/Contacts/4878934000000123456/actions/add_tags
Body: { "tags": [{ "name": "VIP" }] }

# Remove Tag from a record
POST /crm/v7/Contacts/4878934000000123456/actions/remove_tags
Body: { "tags": [{ "name": "VIP" }] }

Required Fields per Module

These are the system-mandatory fields for creating records. The AI agent knows which fields are required and will collect them from the customer before creating.

ModuleRequired FieldsNotes
ContactLast_NameOnly last name needed
LeadLast_Name, CompanyBoth must be provided
AccountAccount_NameCompany/org name
DealDeal_Name, Stage, Closing_DateClosing_Date is YYYY-MM-DD format
CaseSubject, Status, Case_OriginAI defaults: Status=New, Origin=Phone
TaskSubjectOnly subject needed
CallSubject, Call_Type, Call_Start_Time, Call_DurationDuration in mm:ss format (e.g. 05:00)
EventEvent_Title, Start_DateTime, End_DateTimeISO 8601 format. Remind_At auto-set to 15 min
NoteNote_Title, Note_Content, Parent_Id, se_modulese_module = parent module (e.g. Contacts)
ProductProduct_NameOnly product name needed
QuoteSubject, Quoted_ItemsQuoted_Items is an array of line items
AppointmentAppointment_Name, Start_DateTime, End_DateTimeISO 8601 format
SolutionSolution_TitleOnly solution title needed

Step 3: Enable on Your AI Agent

  1. 1Go to AI Agents → select your employee → Edit
  2. 2Scroll to Integrations section
  3. 3Toggle on Zoho CRM and select which actions the employee can use
  4. 4Save. The AI will now use Zoho CRM during calls and widget conversations when relevant

Example Conversation

Here's how your AI agent uses Zoho CRM during a real phone call:

Caller: “Hi, this is John Smith from Acme Corp. I need help with my order.”

AI Agent: “Let me look you up, John.”

→ Executes: search_contact with search_term=“John Smith”

AI Agent: “I found your record, John. Let me create a support case for your order issue.”

→ Executes: create_case with Subject=“Order issue - John Smith”, Status=“New”, Case_Origin=“Phone”

AI Agent: “I've created case for you. Would you like me to schedule a callback with our specialist?”

Caller: “Yes, tomorrow at 2 PM please.”

→ Executes: create_event with Event_Title=“Callback - John Smith order issue”

AI Agent: “Done! I've scheduled a callback for tomorrow at 2 PM. I'll also log this call.”

→ Executes: log_call with Subject=“Inbound - John Smith order inquiry”, Call_Type=“Inbound”

Zoho-Specific Notes

Body wrapper: All Zoho create and update operations wrap the data in {"data": [{...}]}. The templates handle this automatically, so you don't need to add it manually.

Field naming: Zoho uses Title_Case_Underscores for field names (e.g. Last_Name, Deal_Name, Account_Name). This is different from HubSpot (camelCase) and Salesforce (PascalCase).

Updates use PUT: Zoho uses PUT instead of PATCH for updates, but it behaves as a partial update. Only the fields you send are changed and other fields are left untouched.

Search minimum: The word search parameter requires at least 2 characters. Single-character searches return an error. No results returns HTTP 204 (empty body), not an error.

Lookup fields: To link records (e.g. assign a Task to a Contact), use the object format: "Who_Id": {"id": "record_id_here"}. Plain string IDs won't work for lookup fields. You can add lookup fields by editing the action after creating it from a template.

Custom Actions from Scratch

Need something not covered by the 60 templates? You can create custom actions using any Zoho CRM API v7 endpoint. Here are some examples:

Search by Phone Number

Use the phone parameter for exact phone field matching:

GET /crm/v7/Contacts/search?phone={{caller_phone}}

Search by Email

Use the email parameter to search across all email fields:

GET /crm/v7/Contacts/search?email={{email}}

Criteria-Based Search

Use the criteria parameter for structured field-level queries:

GET /crm/v7/Leads/search?criteria=(Lead_Status:equals:Contacted)

# Multiple criteria (max 10):
GET /crm/v7/Deals/search?criteria=(Stage:equals:Qualification)and(Amount:greater_than:5000)

# Supported operators: equals, not_equal, starts_with, in,
# greater_than, less_than, greater_equal, less_equal, between

List Records (No Search)

To list records without a search term, use the base module endpoint:

GET /crm/v7/Contacts?fields=First_Name,Last_Name,Email,Phone&per_page=10&sort_by=Modified_Time&sort_order=desc

Available Variables

Use these variables in your custom action endpoints and body templates:

VariableDescriptionExample
{{caller_phone}}Phone number of the current customer+15551234567
{{employee_id}}ID of the AI agent handling the callemp_abc123
{{call_id}}Unique ID of the current call sessioncall_xyz789
{{action.field}}Value from a previous action result{{search_contact.id}}

Error Handling

Common Zoho API errors you may encounter:

Error CodeHTTP StatusMeaning
MANDATORY_NOT_FOUND400A required field is missing
INVALID_DATA400Invalid value, wrong type, or search term too short
DUPLICATE_DATA400Duplicate value in a unique field
AUTHENTICATION_FAILURE401Token expired or invalid (auto-refresh should handle this)
NO_PERMISSION403User lacks permission for this module
RECORD_NOT_FOUND404The record ID does not exist

Manual Setup (Advanced)

If you prefer not to use OAuth, you can manually configure the connection using a Self Client in the Zoho API Console. This is only recommended for advanced users.

  1. 1Go to Zoho API Console → Add Client → Self Client
  2. 2Note your Client ID and Client Secret
  3. 3Generate a grant token with scopes: ZohoCRM.modules.ALL, ZohoCRM.settings.ALL
  4. 4Exchange the grant token for access + refresh tokens
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_GRANT_TOKEN"

# For EU region: use https://accounts.zoho.eu/oauth/v2/token
# For India: use https://accounts.zoho.in/oauth/v2/token
FieldValue
Connection NameZoho CRM
Base URLhttps://www.zohoapis.com (or regional variant)
Auth TypeBearer Token
TokenYour access_token
Token ExpiresEnabled (1 hour)
Auto-RefreshEnabled
Token URLhttps://accounts.zoho.com/oauth/v2/token
Refresh TokenYour refresh_token
Client IDYour Client ID
Client SecretYour Client Secret

Last updated: February 2026

Zoho CRM Integration | Staffify Docs