Auth
OAuth 2.0 via Zoho’s developer console at accounts.zoho.com/developerconsole. Register a Self Client (server-to-server, no user redirect) or Server-Based Client (user authorization required). The grant token is a one-time code, exchanged for a refresh + access token pair. Access tokens last 1 hour; refresh tokens last indefinitely with periodic activity (60-day idle expiry). Store refresh tokens in a secrets manager (Vault, AWS Secrets Manager, Azure Key Vault), rotate the client secret quarterly.
# Exchange grant token for refresh token
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=authorization_code" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "redirect_uri=$REDIRECT_URI" \
-d "code=$GRANT_TOKEN"
# Refresh access token
curl -X POST "https://accounts.zoho.com/oauth/v2/token" \
-d "grant_type=refresh_token" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "refresh_token=$REFRESH_TOKEN"
Modules
API v8 (current as of 2026) covers Leads, Contacts, Accounts, Deals, Tasks, Events, Calls, Notes, custom modules, and metadata. Each module exposes standard CRUD (GET /Leads, POST /Leads, PUT /Leads/{id}, DELETE /Leads/{id}) plus search (GET /Leads/search?criteria=...), upsert (POST /Leads/upsert), mass update (POST /Leads/actions/mass_update), and convert (POST /Leads/{id}/actions/convert). The metadata API (GET /settings/modules) returns field definitions, layouts, and validation rules — essential for any code that creates records dynamically.
Rate Limits
Per-org daily call cap (Enterprise: 250k, Ultimate: 500k as base with credit-based scaling). Concurrent call cap of 100 per user. Bulk APIs have separate limits — Bulk Read jobs are 100/day, Bulk Write jobs 200/day. Track usage via GET /org/usage. The X-RATELIMIT-REMAINING header on every response shows your remaining daily budget; alert at 20% remaining so you don’t get cut off mid-day. Rate-limit errors return HTTP 429 with Retry-After header — implement exponential backoff with jitter.
Bulk APIs
Bulk Read for exports (returns up to 200k records per job in CSV), Bulk Write for imports (up to 25k records per upload). Both are async — submit job, poll /bulk/v8/read/{job_id} or /bulk/v8/write/{job_id} for status, fetch results when complete. Use for anything over 200 records to avoid hammering the standard API. Bulk Write supports upsert with custom external ID matching — useful for syncing from external systems with their own primary keys.
Webhooks
Configure per-module webhooks on create/edit/delete via the Notification API. Destination URL receives a JSON payload with the changed record. Webhooks are signed with the configured token (HMAC-SHA256 over the body) — verify the signature in your endpoint before processing. Webhooks retry up to 5 times on non-2xx responses with exponential backoff; after that, the event is dropped. Build an idempotency check (e.g. dedup on event ID + record ID + timestamp) because retries can produce duplicates.
What Changed in API v8 (2026)
V8 deprecated v2 and v2.1 endpoints (sunset by end of 2026). Field-level encryption is now declarable via metadata. The fields query parameter became required on GET requests for performance — implicit “return all fields” is gone. Composite operations (transactionally update multiple modules in one call) are new in v8.
What to do this week
Audit your integration code for v2/v2.1 endpoint references and migrate to v8, implement the X-RATELIMIT-REMAINING alerting, and verify webhook signature validation is in place on every consumer endpoint.