A comprehensive skill for authenticating and interacting with Zoho APIs (CRM, Books, Desk, Creator, and more).
Scanned 2/12/2026
Install via CLI
openskills install openclaw/skills# Zoho API Skill for OpenClaw
A comprehensive skill for authenticating and interacting with Zoho APIs (CRM, Books, Desk, Creator, and more).
## Overview
Zoho is a business SaaS platform offering:
- **Zoho CRM** - Sales and contact management
- **Zoho Books** - Accounting and invoicing
- **Zoho Desk** - Customer support ticketing
- **Zoho Creator** - Low-code application development
- **Zoho Campaigns** - Email marketing
- **Zoho Inventory** - Stock management
- **Zoho Projects** - Project management
- **And 50+ more business apps!**
This skill enables secure OAuth2 authentication and API interactions with all Zoho products.
## Setup
### 1. Create Zoho API Client
**Step 1:** Go to Zoho Developer Console
🔗 https://api-console.zoho.com/
**Step 2:** Create a new client
- Click "Add Client"
- Choose "Server-based Application" (recommended)
- Fill in:
- Client Name: OpenClaw-Zoho
- Homepage URL: https://openclaw.ai
- Authorized Redirect URIs: https://openclaw.ai/callback
**Step 3:** Copy your credentials
- **Client ID:** `xxxxxx`
- **Client Secret:** `xxxxxx`
---
### 2. Generate Refresh Token
**Step 1:** Construct OAuth URL
```bash
# Replace values in brackets []
https://accounts.zoho.com/oauth/v2/auth?
scope=ZohoCRM.modules.ALL&
client_id=[YOUR_CLIENT_ID]&
response_type=code&
access_type=offline&
redirect_uri=[YOUR_REDIRECT_URI]
```
**Step 2:** Open URL in browser
- You'll be redirected to Zoho login
- Click "Accept" to authorize
**Step 3:** Copy the authorization code from redirect URL
**Step 4:** Exchange code for tokens
```bash
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=authorization_code" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "redirect_uri=$ZOHO_REDIRECT_URI" \
-d "code=[AUTHORIZATION_CODE]"
```
**Response:**
```json
{
"access_token": "1000.xxxxxx",
"expires_in": 3600,
"refresh_token": "1000.xxxxxx"
}
```
**Step 5:** Save the refresh token securely!
---
### 3. Set Environment Variables
Create a `.env` file or set in your system:
```bash
# Required
export ZOHO_CLIENT_ID="your-client-id"
export ZOHO_CLIENT_SECRET="your-client-secret"
export ZOHO_REFRESH_TOKEN="your-refresh-token"
# Optional (defaults shown)
export ZOHO_DATA_CENTER="com" # com, eu, cn, au, in, jp
export ZOHO_REDIRECT_URI="https://openclaw.ai/callback"
```
**Data Centers:**
| Code | Region |
|------|--------|
| com | US (default) |
| eu | Europe |
| cn | China |
| au | Australia |
| in | India |
| jp | Japan |
---
### 4. Generate Access Token
Zoho access tokens expire in **1 hour**. Always use refresh token:
```bash
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=refresh_token" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "refresh_token=$ZOHO_REFRESH_TOKEN"
```
**Response:**
```json
{
"access_token": "1000.xxxxxx",
"expires_in": 3600
}
```
---
## Zoho CRM API
### Base URLs
| Data Center | Base URL |
|-------------|----------|
| US | `https://www.zohoapis.com/crm/v2` |
| EU | `https://www.zohoapis.eu/crm/v2` |
| AU | `https://www.zohoapis.com.au/crm/v2` |
| IN | `https://www.zohoapis.in/crm/v2` |
---
### 🔍 Get All Modules
```bash
curl -X GET "[BASE_URL]/settings/modules" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
### 👥 CRM Leads Management
#### Get All Leads
```bash
curl -X GET "[BASE_URL]/Leads" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json"
```
**Response:**
```json
{
"data": [
{
"id": "1234567890",
"Company": "South Indian AB",
"Last_Name": "Ravi",
"First_Name": "Customer",
"Email": "customer@example.com",
"Phone": "+46700000000",
"Status": "Not Contacted"
}
],
"info": {
"page": 1,
"per_page": 200,
"total_count": 50
}
}
```
---
#### Create New Lead
```bash
curl -X POST "[BASE_URL]/Leads" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Company": "South Indian AB",
"Last_Name": "Ravi",
"First_Name": "Customer",
"Email": "customer@example.com",
"Phone": "+46700000000",
"Lead_Source": "Website",
"Industry": "Technology"
}
]
}'
```
---
#### Update Lead
```bash
curl -X PUT "[BASE_URL]/Leads/[LEAD_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Phone": "+46709999999",
"Status": "Contacted"
}
]
}'
```
---
#### Delete Lead
```bash
curl -X DELETE "[BASE_URL]/Leads/[LEAD_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
### 💼 CRM Deals Management
#### Create Deal
```bash
curl -X POST "[BASE_URL]/Deals" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Deal_Name": "Annual Software License - South Indian AB",
"Amount": 50000,
"Closing_Date": "2026-03-31",
"Stage": "Needs Analysis",
"Pipeline": "Standard",
"Account_Name": "1234567890"
}
]
}'
```
---
#### Get Deals by Stage
```bash
curl -X GET "[BASE_URL]/Deals?stage=Closed Won" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
### 👤 CRM Contacts Management
#### Create Contact
```bash
curl -X POST "[BASE_URL]/Contacts" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"First_Name": "Ravi",
"Last_Name": "Senthazal",
"Email": "ravi@example.com",
"Phone": "+46701234567",
"Mailing_Street": "Drottninggatan 1",
"Mailing_City": "Stockholm",
"Mailing_Country": "Sweden"
}
]
}'
```
---
### 🏢 CRM Accounts/Companies Management
#### Create Account
```bash
curl -X POST "[BASE_URL]/Accounts" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Name": "South Indian Restaurant AB",
"Phone": "+4681234567",
"Website": "https://southindian.se",
"Industry": "Restaurant",
"Billing_City": "Stockholm",
"Billing_Country": "Sweden",
"Type": "Customer"
}
]
}'
```
---
### 📝 CRM Notes & Activities
#### Add Note to Record
```bash
curl -X POST "[BASE_URL]/Notes" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"Note_Title": "Follow-up Call Scheduled",
"Note_Content": "Customer requested follow-up call next week.",
"Parent_Id": "[LEAD_ID]",
"Parent_Name": "Leads"
}
]
}'
```
---
## Zoho Books API
### Base URLs
| Data Center | Base URL |
|-------------|----------|
| US | `https://www.zohoapis.com/books/v3` |
| EU | `https://www.zohoapis.eu/books/v3` |
| AU | `https://www.zohoapis.com.au/books/v3` |
**Important:** All requests require `organization_id` parameter!
---
### 🔐 Authentication for Books
Use the same OAuth tokens. Books uses CRM tokens by default!
---
### 👤 Books - Customer Management
#### Get All Customers
```bash
curl -X GET "https://www.zohoapis.com/books/v3/contacts?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
#### Create Customer
```bash
curl -X POST "https://www.zohoapis.com/books/v3/contacts?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"contact_name": "South Indian AB",
"company_name": "South Indian Restaurant AB",
"email": "billing@southindian.se",
"phone": "+4681234567",
"billing_address": {
"street": "Drottninggatan 1",
"city": "Stockholm",
"state": "Stockholm County",
"zip": "11123",
"country": "Sweden"
}
}'
```
---
### 💰 Books - Invoicing
#### Create Invoice
```bash
curl -X POST "https://www.zohoapis.com/books/v3/invoices?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "1234567890",
"date": "2026-02-05",
"due_date": "2026-03-05",
"line_items": [
{
"name": "South Indian Dinner Buffet",
"description": "2 Adults, Weekend Package",
"rate": 399,
"quantity": 2,
"item_id": "1234567890"
},
{
"name": "Welcome Drinks",
"rate": 49,
"quantity": 2,
"item_id": "1234567891"
}
],
"notes": "Thank you for dining with us!",
"terms": "Payment due within 30 days."
}'
```
---
#### Get Invoice Status
```bash
curl -X GET "https://www.zohoapis.com/books/v3/invoices/[INVOICE_ID]?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
#### Send Invoice to Customer
```bash
curl -X POST "https://www.zohoapis.com/books/v3/invoices/[INVOICE_ID]/actions/send?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to_mail_ids": ["customer@example.com"]
}'
```
---
### 📊 Books - Expense Tracking
#### Create Expense
```bash
curl -X POST "https://www.zohoapis.com/books/v3/expenses?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-02-05",
"amount": 1500,
"account_id": "1234567890",
"description": "Weekly ingredient supply - spices",
"vendor_id": "1234567890",
"tax_id": "1234567890"
}'
```
---
### 📈 Books - Reports
#### Get Profit & Loss Report
```bash
curl -X GET "https://www.zohoapis.com/books/v3/reports/profitandloss?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
## Zoho Desk API
### Base URLs
| Data Center | Base URL |
|-------------|----------|
| US | `https://desk.zoho.com/api/v1` |
| EU | `https://desk.zoho.eu/api/v1` |
| AU | `https://desk.zoho.com.au/api/v1` |
---
### 🎫 Ticket Management
#### Get All Tickets
```bash
curl -X GET "https://desk.zoho.com/api/v1/tickets?departmentId=[DEPT_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
#### Create Ticket
```bash
curl -X POST "https://desk.zoho.com/api/v1/tickets" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": "Table Reservation Issue",
"departmentId": "1234567890",
"contact": {
"lastName": "Ravi",
"email": "customer@example.com"
},
"description": "Customer reported that their online table reservation was not found in the system.",
"priority": "High",
"status": "Open"
}'
```
---
#### Update Ticket
```bash
curl -X PUT "https://desk.zoho.com/api/v1/tickets/[TICKET_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "In Progress",
"priority": "High",
"assigneeId": "1234567890"
}'
```
---
#### Add Comment to Ticket
```bash
curl -X POST "https://desk.zoho.com/api/v1/tickets/[TICKET_ID]/comments" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Contacted customer, issue resolved. Reservation updated in system.",
"isPublic": true
}'
```
---
## Zoho Creator API
### Base URLs
| Data Center | Base URL |
|-------------|----------|
| US | `https://creator.zoho.com/api/v2` |
| EU | `https://creator.zoho.eu/api/v2` |
---
### 📝 Submit Form Data
```bash
curl -X POST "https://creator.zoho.com/api/v2/[APP_LINK_NAME]/[FORM_LINK_NAME]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"Name": "Employee Onboarding",
"Employee_Name": "John Doe",
"Department": "Engineering",
"Start_Date": "2026-03-01",
"Manager": "Jane Smith"
}
}'
```
---
### 📊 Get Form Records
```bash
curl -X GET "https://creator.zoho.com/api/v2/[APP_LINK_NAME]/[FORM_LINK_NAME]?MaxRows=100" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
## Zoho Campaigns API
### Base URL
`https://campaigns.zoho.com/api/v1`
---
### 📧 Create Campaign
```bash
curl -X POST "https://campaigns.zoho.com/api/v1/campaigns" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"campaign_name": "February Restaurant Promotion",
"subject": "🍛 Special Offer: 20% Off South Indian Thali!",
"from_name": "South Indian Restaurant",
"from_email": "marketing@southindian.se",
"reply_to": "info@southindian.se"
}'
```
---
### 👥 Manage Lists
```bash
# Get all mailing lists
curl -X GET "https://campaigns.zoho.com/api/v1/lists" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
---
## Advanced Features
### 🔄 Auto Token Refresh Script
Create a helper script `refresh-zoho-token.sh`:
```bash
#!/bin/bash
# Refresh Zoho access token
RESPONSE=$(curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=refresh_token" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "refresh_token=$ZOHO_REFRESH_TOKEN")
# Extract access token
ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token')
# Export for current session
export ZOHO_ACCESS_TOKEN=$ACCESS_TOKEN
echo "Token refreshed: $ACCESS_TOKEN"
```
Run it:
```bash
chmod +x refresh-zoho-token.sh
./refresh-zoho-token.sh
```
---
### 📡 Webhooks Setup
Zoho can send real-time updates to your endpoints:
**Configure in Zoho:**
1. Go to Settings → Webhooks
2. Add webhook URL: `https://your-server.com/api/zoho-webhook`
3. Select triggers (e.g., `on_lead_create`, `on_deal_update`)
**Handle webhook in your app:**
```javascript
// Express.js example
app.post('/api/zoho-webhook', (req, res) => {
const { module, data, event } = req.body;
console.log(`Zoho Webhook: ${event} on ${module}`);
console.log('Data:', data);
// Process the update
if (module === 'Leads') {
// Handle new lead
handleNewLead(data);
}
res.status(200).send('OK');
});
```
---
### 🔗 Multi-Product Workflows
#### Example: Restaurant Customer to Invoice Flow
```bash
# 1. Customer books table (Zoho Creator form)
curl -X POST "https://creator.zoho.com/api/v2/restaurant/bookings" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"Customer_Name": "Ravi",
"Email": "ravi@example.com",
"Date": "2026-02-14",
"Guests": 4,
"Special_Requests": "Window seat preferred"
}
}'
```
```bash
# 2. Create CRM contact
curl -X POST "https://www.zohoapis.com/crm/v2/Contacts" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": [{
"First_Name": "Ravi",
"Email": "ravi@example.com",
"Source": "Table Booking"
}]
}'
```
```bash
# 3. After dining, create invoice
curl -X POST "https://www.zohoapis.com/books/v3/invoices?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "[CUSTOMER_ID]",
"date": "2026-02-14",
"line_items": [{
"name": "Valentine's Day Special Thali",
"rate": 499,
"quantity": 4
}]
}'
```
---
## Error Handling
### Common Error Codes
| Code | Meaning | Solution |
|------|---------|----------|
| 401 | Invalid token | Refresh your access token |
| 400 | Bad request | Check JSON syntax |
| 403 | Forbidden | Check API permissions |
| 404 | Not found | Verify record ID |
| 429 | Rate limit | Wait and retry |
| 500 | Server error | Retry later |
---
### Retry Logic Example
```bash
# Function to call Zoho API with retry
call_zoho_api() {
local url=$1
local method=$2
local data=$3
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
response=$(curl -s -o /dev/null -w "%{http_code}" \
-X $method "$url" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "$data")
if [ $response -eq 200 ] || [ $response -eq 201 ]; then
echo "Success!"
return 0
elif [ $response -eq 429 ]; then
echo "Rate limited, waiting 60s..."
sleep 60
else
echo "Error: $response"
fi
attempt=$((attempt + 1))
sleep 5
done
echo "Failed after $max_attempts attempts"
return 1
}
```
---
## Environment Variables Reference
| Variable | Required | Description |
|----------|----------|-------------|
| `ZOHO_CLIENT_ID` | ✅ | OAuth Client ID |
| `ZOHO_CLIENT_SECRET` | ✅ | OAuth Client Secret |
| `ZOHO_REFRESH_TOKEN` | ✅ | Long-lived refresh token |
| `ZOHO_ACCESS_TOKEN` | ❌ | Short-lived (auto-generated) |
| `ZOHO_DATA_CENTER` | ❌ | `com` (default), `eu`, `au`, `in` |
| `ZOHO_REDIRECT_URI` | ❌ | OAuth redirect URL |
| `ZOHO_ORG_ID` | ❌ | Books/Desk organization ID |
---
## Use Cases
### 🍽️ Restaurant Business
| Task | Zoho Product | Example |
|------|-------------|---------|
| Table bookings | Creator | Online reservation form |
| Customer database | CRM | Track dining preferences |
| Invoicing | Books | Monthly billing |
| Support tickets | Desk | Reservation issues |
| Marketing campaigns | Campaigns | New menu announcements |
---
### 🛒 SaaS Business
| Task | Zoho Product | Example |
|------|-------------|---------|
| Lead tracking | CRM | Sales pipeline |
| Customer support | Desk | Technical issues |
| Subscription billing | Books/Subscriptions | Recurring invoices |
| Feature requests | Creator | Feedback portal |
| Email marketing | Campaigns | Product updates |
---
### 🏢 General Business
| Task | Zoho Product | Example |
|------|-------------|---------|
| Contact management | CRM | Company database |
| Project tracking | Projects | Task assignments |
| Expense tracking | Books | Receipt management |
| HR onboarding | Creator | Employee forms |
| IT help desk | Desk | Support tickets |
---
## Security Best Practices
### ✅ Do's
- Store tokens in environment variables
- Use HTTPS for all API calls
- Rotate refresh tokens periodically
- Set up webhook verification
- Use least-privilege API scopes
### ❌ Don'ts
- Never commit tokens to GitHub
- Don't expose access tokens in URLs
- Avoid hardcoding credentials
- Don't share tokens between users
---
## Testing
### Validate Setup
```bash
# Test CRM connection
curl -X GET "https://www.zohoapis.com/crm/v2/settings/modules" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN"
```
Should return module list. If 401, refresh your token!
---
### Test Invoice Creation
```bash
# Create test invoice (amount: 1.00)
curl -X POST "https://www.zohoapis.com/books/v3/invoices?organization_id=[ORG_ID]" \
-H "Authorization: Zoho-oauthtoken $ZOHO_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "[TEST_CUSTOMER_ID]",
"line_items": [{
"name": "Test Item",
"rate": 1,
"quantity": 1
}]
}'
```
---
## Troubleshooting
### "Invalid Token" Error
```bash
# Refresh your access token
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=refresh_token" \
-d "client_id=$ZOHO_CLIENT_ID" \
-d "client_secret=$ZOHO_CLIENT_SECRET" \
-d "refresh_token=$ZOHO_REFRESH_TOKEN"
```
---
### "Rate Limit Exceeded"
- Wait 60 seconds before retrying
- Implement exponential backoff
- Reduce API call frequency
- Contact Zoho support for higher limits
---
### "Module Not Found"
Verify module name spelling:
- ✅ `Leads`, `Contacts`, `Deals`, `Accounts`
- ❌ `Lead`, `Contact`, `Deal`, `Account`
---
### Permission Denied
Check your OAuth scopes:
- `ZohoCRM.modules.ALL` for full CRM access
- `ZohoBooks.fullaccess` for Books
- `ZohoDesk.fullaccess.all` for Desk
---
## Resources
### Official Documentation
- **Zoho CRM API:** https://www.zoho.com/crm/developer/docs/api/v2/
- **Zoho Books API:** https://www.zoho.com/books/developer/docs/api/v3/
- **Zoho Desk API:** https://desk.zoho.com/developer/docs/api/v1/
- **Zoho Creator API:** https://www.zoho.com/creator/developer/docs/api/v2/
### Tools
- **API Console:** https://api-console.zoho.com/
- **Developer Hub:** https://www.zoho.com/developer/
### Support
- **Zoho Community:** https://help.zoho.com/
- **Developer Forums:** https://forums.zoho.com/
---
## Version
- **Current:** 1.0.0
- **Created:** 2026-02-05
- **Author:** OpenClaw Community
---
**Happy Zoho Automation!** 🚀📊
Questions? Check the troubleshooting section or Zoho's official docs!
No comments yet. Be the first to comment!