Zoho Books/Inventory/CRM REST API Capabilities and Rate Limits

Type: ERP Integration System: Zoho Books (API v3), Zoho Inventory (API v1), Zoho CRM (API v7/v8) Confidence: 0.91 Sources: 8 Verified: 2026-03-02 Freshness: 2026-03-02

TL;DR

System Profile

This card covers the REST APIs for three core Zoho business applications — Zoho Books (accounting), Zoho Inventory (warehouse and order management), and Zoho CRM (customer relationship management). These three products share Zoho's OAuth 2.0 authentication infrastructure but have entirely separate API endpoints, rate limits, and capabilities. This card does NOT cover Zoho People, Zoho Desk, Zoho Projects, or other Zoho One suite products.

SystemAPI VersionBase URLAPI Docs
Zoho Booksv3https://www.zohoapis.com/books/v3Books API v3
Zoho Inventoryv1https://www.zohoapis.com/inventory/v1Inventory API v1
Zoho CRMv7/v8https://www.zohoapis.com/crm/v7 or /v8CRM API v8

API Surfaces & Capabilities

API SurfaceProtocolBest ForMax Records/RequestRate LimitReal-time?Bulk?
Zoho Books REST v3HTTPS/JSONInvoices, expenses, banking, contacts, accounting200 per page100 req/min + daily capYesNo
Zoho Inventory REST v1HTTPS/JSONItems, sales/purchase orders, packages, shipments200 per page100 req/min + daily capYesNo
Zoho CRM REST v7/v8HTTPS/JSONLeads, contacts, deals, accounts, modules CRUD200 (GET), 100 (write)Credit-based + concurrencyYesNo
Zoho CRM Bulk APIHTTPS/CSVData migration, backup, batch sync > 2K records25,000 per file50/500 credits per jobNo (async)Yes
Zoho CRM COQLHTTPS/JSONComplex record queries with joins and conditions200-2,000 per query1-3 credits per queryYesNo
Zoho CRM NotificationsHTTPS/JSONReal-time record change notificationsN/AIncluded in CRM limitsYesN/A
Zoho CRM WebhooksHTTPS/JSONEvent-driven outbound notificationsN/AWorkflow-triggeredYesN/A

Rate Limits & Quotas

Per-Request Limits

Limit TypeValueApplies ToNotes
Max records per GET (Books/Inventory)200 per pageList endpointsUse page and per_page parameters
Max records per GET (CRM)200 per requestGet Records APIUse page token for pagination
Max records per write (CRM)100 per requestInsert/Update/UpsertEach 10 records = 1 credit
Max COQL query results200-2,000CRM COQL API1-3 credits depending on limit
Max bulk file size (CRM)25,000 records per CSVBulk Read/Write APIAsync processing

Zoho Books & Inventory — Rolling / Daily Limits

PlanDaily LimitPer-Minute LimitConcurrent Calls
Free1,000 requests/day100/min5
Standard2,000 requests/day100/min10
Professional5,000 requests/day100/min10
Premium / Elite / Ultimate (Books)10,000 requests/day100/min10
Premium / Enterprise (Inventory)10,000 requests/day100/min10

Zoho CRM — Credit-Based System (24h Rolling Window)

EditionBase CreditsPer-User CreditsMax Credits/24hConcurrent CallsSub-Concurrency
Free5,0005,000510
Standard/Starter50,000+250/user100,0001010
Professional50,000+500/user3,000,0001510
Enterprise/Zoho One50,000+1,000/user5,000,0002010
Ultimate/CRM Plus50,000+2,000/userUnlimited2510

CRM API Credit Costs

OperationCredit CostNotes
Standard metadata/user retrieval1 creditOrg info, users, roles, profiles
Get Records (standard)1 creditUp to 200 records
Get Records via COQL (1-200)1 creditQuery language interface
Get Records via COQL (201-1,000)2 creditsHigher page sizes cost more
Get Records via COQL (1,001-2,000)3 creditsMaximum COQL page size
Insert/Update/Upsert1 credit per 10 recordsBulk within single request
Convert Lead5 creditsCreates Contact + Account + Deal
Send Mail20 creditsEmail operations are expensive
Merge Records50 creditsDeduplication merges
Bulk Read Initialize50 creditsAsync bulk export job
Bulk Write Initialize500 creditsAsync bulk import job
Mass Convert Leads200 creditsBatch lead conversion

Authentication

All Zoho APIs authenticate via OAuth 2.0 through Zoho's accounts server. The token endpoint varies by data center region. [src5]

FlowUse WhenToken LifetimeRefresh?Notes
Self Client — Client CredentialsServer-to-server, backend jobsAccess: 1 hourNo refresh token; request new each hourRecommended for integrations. grant_type=client_credentials
Self Client — Authorization CodeBackend scripts with user scopesAccess: 1 hour; Refresh: never expiresYes — permanent refresh tokenGenerate code in API Console (3-min expiry)
Server-based App — Auth CodeWeb apps with user interactionAccess: 1 hour; Refresh: never expiresYesStandard OAuth 2.0 with redirect URI
Client-side AppSPAs and mobile appsAccess: 1 hourLimitedUses implicit or PKCE flow

Regional Token Endpoints

Data CenterAccounts Server URL
US (.com)https://accounts.zoho.com/oauth/v2/token
EU (.eu)https://accounts.zoho.eu/oauth/v2/token
India (.in)https://accounts.zoho.in/oauth/v2/token
Australia (.com.au)https://accounts.zoho.com.au/oauth/v2/token
Japan (.jp)https://accounts.zoho.jp/oauth/v2/token
Canada (.ca)https://accounts.zohocloud.ca/oauth/v2/token
China (.com.cn)https://accounts.zoho.com.cn/oauth/v2/token
Saudi Arabia (.sa)https://accounts.zoho.sa/oauth/v2/token

Authentication Gotchas

Constraints

Integration Pattern Decision Tree

START — User needs to integrate with Zoho Books, Inventory, or CRM
├── Which Zoho product?
│   ├── Zoho Books (accounting)
│   │   ├── Daily volume < 1,000 records? → REST API (any plan)
│   │   ├── Need real-time sync? → REST API with 100/min throttling
│   │   └── Need >10K ops/day? → Not possible via API — use CSV import
│   ├── Zoho Inventory (warehouse/orders)
│   │   └── Same limits as Books (100/min, daily cap by plan)
│   └── Zoho CRM (customer data)
│       ├── < 2K records/op? → REST API with credit tracking
│       ├── > 2K records? → Bulk API (async CSV)
│       ├── Complex queries? → COQL API (SQL-like, 200-2K results)
│       └── Need notifications? → Webhooks or Notification API
├── Authentication type?
│   ├── Server-to-server → Self Client: client_credentials
│   ├── Backend + user context → Self Client: authorization code
│   └── Web/mobile app → Server-based or client-side flow
└── Error tolerance?
    ├── Zero-loss → retry queue + dead letter + idempotency
    └── Best-effort → retry on 429 with exponential backoff

Quick Reference

Zoho Books API v3 — Key Endpoints

OperationMethodEndpointNotes
List invoicesGET/books/v3/invoices?organization_id={org_id}Paginated, 200/page max
Create invoicePOST/books/v3/invoices?organization_id={org_id}JSON body with line items
Get invoiceGET/books/v3/invoices/{invoice_id}?organization_id={org_id}Single record
Update invoicePUT/books/v3/invoices/{invoice_id}?organization_id={org_id}Full or partial update
Delete invoiceDELETE/books/v3/invoices/{invoice_id}?organization_id={org_id}Soft delete
List contactsGET/books/v3/contacts?organization_id={org_id}Customers and vendors
List itemsGET/books/v3/items?organization_id={org_id}Products/services
List expensesGET/books/v3/expenses?organization_id={org_id}Expense records

Zoho Inventory API v1 — Key Endpoints

OperationMethodEndpointNotes
List itemsGET/inventory/v1/items?organization_id={org_id}Product catalog
Create itemPOST/inventory/v1/items?organization_id={org_id}With variants support
List sales ordersGET/inventory/v1/salesorders?organization_id={org_id}Sales pipeline
List purchase ordersGET/inventory/v1/purchaseorders?organization_id={org_id}Procurement
List packagesGET/inventory/v1/packages?organization_id={org_id}Shipment packaging
List transfer ordersGET/inventory/v1/transferorders?organization_id={org_id}Inter-warehouse

Zoho CRM API v7/v8 — Key Endpoints

OperationMethodEndpointCreditsNotes
Get recordsGET/crm/v7/{module}1Max 200 records/page
Create recordsPOST/crm/v7/{module}1 per 10 recordsMax 100 records/request
Update recordsPUT/crm/v7/{module}1 per 10 recordsMax 100 records/request
Upsert recordsPOST/crm/v7/{module}/upsert1 per 10 recordsDeduplicate on unique fields
Search recordsGET/crm/v7/{module}/search1Criteria-based search
COQL queryPOST/crm/v7/coql1-3SQL-like queries
Bulk readPOST/crm/v7/bulk-read50Async CSV export
Bulk writePOST/crm/v7/bulk-write500Async CSV import
Convert leadPOST/crm/v7/Leads/{id}/actions/convert5Creates Contact + Account + Deal

Step-by-Step Integration Guide

1. Register a Self Client in Zoho API Console

Navigate to Zoho API Console and create a Self Client. Copy the Client ID and Client Secret. [src5]

# No CLI — use Zoho API Console (https://api-console.zoho.com/)
# Record: Client ID, Client Secret, Data center domain

Verify: Client ID and Client Secret appear in API Console under Self Client > Client Secret tab.

2. Generate access token using client credentials flow

For server-to-server integrations, use the client_credentials grant type. [src5]

curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  -d "scope=ZohoBooks.invoices.READ,ZohoInventory.items.READ,ZohoCRM.modules.READ" \
  -d "soid=ZohoBooks.{zsoid}"

Verify: Response contains access_token and expires_in: 3600.

3. Call Zoho Books API — list organizations

Retrieve your organization ID, required on every subsequent Books/Inventory API call. [src3]

curl -s "https://www.zohoapis.com/books/v3/organizations" \
  -H "Authorization: Zoho-oauthtoken YOUR_ACCESS_TOKEN"

Verify: Response code is 0 and organizations array is non-empty.

4. Implement rate-limited API calls with retry logic

Wrap all calls with rate limit awareness. Books/Inventory return 429 when exceeding 100/min or daily caps. [src6]

import time, requests

class ZohoRateLimiter:
    def __init__(self, access_token, org_id, base_url="https://www.zohoapis.com"):
        self.token = access_token
        self.org_id = org_id
        self.base_url = base_url
        self.headers = {
            "Authorization": f"Zoho-oauthtoken {access_token}",
            "Content-Type": "application/json"
        }

    def request(self, method, endpoint, max_retries=5, **kwargs):
        url = f"{self.base_url}{endpoint}"
        params = kwargs.pop("params", {})
        params["organization_id"] = self.org_id
        for attempt in range(max_retries):
            resp = requests.request(method, url, headers=self.headers, params=params, **kwargs)
            if resp.status_code == 429:
                wait = min(2 ** attempt * 2, 60)
                time.sleep(wait)
                continue
            return resp.json()
        raise Exception("Max retries exceeded")

Verify: Calling limiter.request("GET", "/books/v3/invoices") returns JSON with code: 0.

Code Examples

Python: Sync Zoho Books invoices with pagination

# Input:  access_token, organization_id
# Output: All invoices from Zoho Books (paginated)

import requests, time

TOKEN = "YOUR_ACCESS_TOKEN"
ORG_ID = "YOUR_ORG_ID"
BASE = "https://www.zohoapis.com/books/v3"
headers = {"Authorization": f"Zoho-oauthtoken {TOKEN}"}

def get_all_invoices():
    all_invoices, page, has_more = [], 1, True
    while has_more:
        resp = requests.get(f"{BASE}/invoices", headers=headers,
            params={"organization_id": ORG_ID, "page": page, "per_page": 200})
        if resp.status_code == 429:
            time.sleep(60); continue
        data = resp.json()
        all_invoices.extend(data.get("invoices", []))
        has_more = data.get("page_context", {}).get("has_more_page", False)
        page += 1; time.sleep(0.6)  # stay under 100/min
    return all_invoices

JavaScript/Node.js: Create CRM records with credit tracking

// Input:  access_token, module name, records array
// Output: Created record IDs with credit usage estimate
// npm install axios@1

const axios = require("axios");
const TOKEN = process.env.ZOHO_ACCESS_TOKEN;

async function createRecords(module, records) {
  const chunks = [];
  for (let i = 0; i < records.length; i += 100) chunks.push(records.slice(i, i + 100));
  const results = []; let totalCredits = 0;
  for (const chunk of chunks) {
    try {
      const resp = await axios.post(`https://www.zohoapis.com/crm/v7/${module}`,
        { data: chunk },
        { headers: { Authorization: `Zoho-oauthtoken ${TOKEN}`, "Content-Type": "application/json" } });
      results.push(...resp.data.data);
      totalCredits += Math.ceil(chunk.length / 10);
    } catch (err) {
      if (err.response?.status === 429) { await new Promise(r => setTimeout(r, 5000)); continue; }
      throw err;
    }
  }
  console.log(`Created ${results.length} records, ~${totalCredits} credits`);
  return results;
}

cURL: Quick API test across all three products

# Input:  access_token, organization_id
# Output: Verification that auth works for all three APIs

TOKEN="YOUR_ACCESS_TOKEN"; ORG_ID="YOUR_ORG_ID"

# Test Zoho Books
curl -s "https://www.zohoapis.com/books/v3/organizations" \
  -H "Authorization: Zoho-oauthtoken $TOKEN" | python3 -m json.tool

# Test Zoho Inventory
curl -s "https://www.zohoapis.com/inventory/v1/items?organization_id=$ORG_ID" \
  -H "Authorization: Zoho-oauthtoken $TOKEN" | python3 -m json.tool

# Test Zoho CRM
curl -s "https://www.zohoapis.com/crm/v7/org" \
  -H "Authorization: Zoho-oauthtoken $TOKEN" | python3 -m json.tool

Data Mapping

Cross-Product Field Mapping (Books <-> Inventory <-> CRM)

Books FieldInventory FieldCRM FieldTypeGotcha
contact_namecontact_nameAccount_NameStringCRM uses Account module; Books/Inventory use Contacts — different entity model
customer_idcontact_ididString (ID)IDs are not shared across products — maintain cross-reference mapping
line_items[].item_idline_items[].item_idProduct_Details[].product.idString (ID)Item IDs sync between Books and Inventory but NOT with CRM Products
totaltotalAmountDecimalCurrency formatting differs by product
datedateClosing_DateDateAll use YYYY-MM-DD but CRM datetime includes timezone offset
statusstatusStageString (enum)Status values differ completely — must map explicitly
currency_codecurrency_codeCurrencyISO 4217Multi-currency must be enabled independently in each product

Data Type Gotchas

Error Handling & Failure Points

Common Error Codes

CodeHTTP StatusMeaningResolution
44429Per-minute rate limit exceededWait 60 seconds. Implement 600ms minimum gap between requests.
45429Daily rate limit exceededWait until next day or upgrade plan.
1070429Concurrent call limit exceededReduce parallelism. Free: max 5, Paid: max 10.
1000500Internal server errorRetry with exponential backoff.
1002404Resource not foundVerify resource ID. Check if record deleted.
401UnauthorizedRefresh token. Verify Zoho-oauthtoken prefix.
INVALID_DATA400Malformed request bodyValidate against API docs.

Failure Points in Production

Anti-Patterns

Wrong: Ignoring rate limits — sending requests as fast as possible

# BAD — will hit 100/min limit on Books/Inventory almost immediately
for invoice in invoices:
    requests.post(f"{BASE}/invoices", headers=headers, json=invoice, params={"organization_id": org_id})

Correct: Implement request throttling with minimum gap

# GOOD — 600ms gap ensures < 100 requests/min for Books/Inventory
import time
for invoice in invoices:
    requests.post(f"{BASE}/invoices", headers=headers, json=invoice, params={"organization_id": org_id})
    time.sleep(0.6)  # 600ms gap = max 100 requests/min

Wrong: Using Bearer prefix for Zoho Books/Inventory

# BAD — Books/Inventory require "Zoho-oauthtoken" prefix, not "Bearer"
curl -H "Authorization: Bearer 1000.xxxx" \
  "https://www.zohoapis.com/books/v3/invoices?organization_id=12345"

Correct: Use Zoho-oauthtoken prefix

# GOOD — correct authorization header format
curl -H "Authorization: Zoho-oauthtoken 1000.xxxx" \
  "https://www.zohoapis.com/books/v3/invoices?organization_id=12345"

Wrong: Hardcoding US data center domain for all orgs

# BAD — breaks for EU, India, Australia, Japan orgs
BASE_URL = "https://www.zohoapis.com"
TOKEN_URL = "https://accounts.zoho.com/oauth/v2/token"

Correct: Use data center domain from configuration

# GOOD — data center domain from config
import os
DC = os.environ.get("ZOHO_DC", "com")  # com, eu, in, com.au, jp, ca
BASE_URL = f"https://www.zohoapis.{DC}"
TOKEN_URL = f"https://accounts.zoho.{DC}/oauth/v2/token"

Common Pitfalls

Diagnostic Commands

# Check remaining API quota (Books — response headers)
curl -I "https://www.zohoapis.com/books/v3/organizations" \
  -H "Authorization: Zoho-oauthtoken YOUR_TOKEN"

# Test authentication — Books
curl -s "https://www.zohoapis.com/books/v3/organizations" \
  -H "Authorization: Zoho-oauthtoken YOUR_TOKEN" | python3 -m json.tool

# Test authentication — CRM
curl -s "https://www.zohoapis.com/crm/v7/org" \
  -H "Authorization: Zoho-oauthtoken YOUR_TOKEN" | python3 -m json.tool

# Get available CRM modules
curl -s "https://www.zohoapis.com/crm/v7/settings/modules" \
  -H "Authorization: Zoho-oauthtoken YOUR_TOKEN" | python3 -m json.tool

# Generate new access token (client_credentials)
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
  -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=client_credentials&scope=ZohoBooks.fullaccess.all,ZohoInventory.fullaccess.all,ZohoCRM.modules.ALL"

# Refresh access token (authorization_code flow)
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
  -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=refresh_token&refresh_token=YOUR_REFRESH_TOKEN"

Version History & Compatibility

ProductAPI VersionReleaseStatusKey Changes
Zoho Booksv32023Current (GA)Latest stable with 40+ modules
Zoho Inventoryv12020Current (GA)Only version available
Zoho CRMv82025-Q3Current (GA)Credit-based limits, Data Sharing APIs, Workflow APIs, OAS 3.0, Zia AI API
Zoho CRMv72024-Q3SupportedImproved webhook/notification APIs
Zoho CRMv62024-Q1SupportedRecord locking, cadences, scoring rules
Zoho CRMv2.12020Deprecated (maintenance)No new features. Migration recommended.
Zoho CRMv12016EOLXML-based, fully retired

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
SMB accounting integration with < 10K transactions/dayEnterprise-scale ERP with > 100K transactions/daySAP, Oracle, NetSuite APIs with higher throughput
Zoho-centric ecosystem (Books + Inventory + CRM)Need high-volume integration with many external systemsiPaaS middleware (Workato, Celigo) with Zoho connectors
Real-time individual record sync with < 100 ops/minHigh-frequency data ingestionStreaming platforms (Kafka, AWS EventBridge)
CRM data migration or bulk exportBooks/Inventory bulk operations (no bulk API)Zoho Books CSV import or scheduled REST batching
Server-to-server integration without user interactionMobile/SPA needing offline accessZoho SDKs with PKCE flow

Cross-System Comparison

CapabilityZoho Books (v3)Zoho Inventory (v1)Zoho CRM (v7/v8)Notes
Rate Limit Model100/min + daily cap100/min + daily capCredit-based + concurrent capCRM is most flexible
Max Daily (top tier)10,000 requests10,000 requestsUnlimited credits (Ultimate)CRM scales much higher
Concurrent Calls (paid)101010-25 (by edition)CRM Enterprise: 20, Ultimate: 25
Bulk APINoneNoneYes (async CSV)Major gap for Books/Inventory
Webhook SupportNoNoYes (Workflow Rules)Books/Inventory lack push notifications
COQL/Query LanguageNoNoYes (SQL-like)CRM-only feature
Paginationpage + per_page (200 max)page + per_page (200 max)page token (200 max)Similar across all three
Auth HeaderZoho-oauthtokenZoho-oauthtokenZoho-oauthtoken or BearerCRM accepts both
API VersioningSingle (v3)Single (v1)Multiple (v2.1-v8)CRM has rich version history
Error Formatcode + message JSONcode + message JSONcode + details JSON arrayCRM errors more structured
Modules/Endpoints40+ (financial)15+ (inventory)50+ (CRM + custom modules)Books has broadest financial coverage

Important Caveats

Related Units