How Zoho CRM Webhooks Work
Zoho CRM doesn’t have a “register a URL, pick events” webhook screen like Pipedrive. A Zoho webhook is an action: you define it once (URL, method, payload), then attach it to a workflow rule that decides when it fires: when a contact is created, a deal is edited, a field changes.
That design is flexible. You can filter with criteria and send exactly the fields you want. But it means one workflow rule per module and trigger, and it comes with limits worth knowing before you build.
There’s also a second option, the Notification API, which suits some integrations better. We cover both below.
In This Post
Prerequisites
- Admin access to Zoho CRM (Setup > Automation)
- API credentials if the integration also writes back to Zoho (Zoho CRM API setup)
- The webhook URL we provide for your integration
Step 1: Create the Webhook
- Go to Setup > Automation > Actions > Webhooks
- Click Configure Webhook
- Name it clearly, e.g. “New contacts to integration”
- Choose the method: POST (normal for integrations), GET, PUT or DELETE. POST and PUT can send headers, a body and URL parameters; GET and DELETE send URL parameters only
- Enter the URL to notify (the endpoint we provide)
- Choose the module (Contacts, Deals, Accounts, Leads…)
- Set authentication (see below)
- Build the body (see the next section) and save
Authentication options
- General: an API key or auth token you add yourself, typically as a header parameter. This is the common choice when the receiving endpoint checks a shared secret.
- Connection: uses a Zoho connection (OAuth, API key and similar) when you’re calling a third-party API directly.
You can add up to 10 header parameters, built from module fields or custom values. We usually add one secret header so our endpoint can reject anything that didn’t come from your Zoho account.
Step 2: Build the Payload
You have two body formats:
- Form-Data: name/value pairs, each mapped to a module field, a custom value or a user-defined value.
- Raw: write the body yourself as JSON, XML, HTML or text (up to 15,000 characters). In the raw editor, type
#to insert a merge field.
For integrations we use Raw JSON, because it’s explicit and easy to validate. A typical contact payload looks like this:
{
"event": "contact.created",
"contact_id": "${Contacts.Contact Id}",
"first_name": "${Contacts.First Name}",
"last_name": "${Contacts.Last Name}",
"email": "${Contacts.Email}",
"phone": "${Contacts.Phone}",
"owner": "${Contacts.Contact Owner}"
}
Insert each ${…} placeholder with the # picker rather than typing it. Zoho fills in the exact field reference for your module, and field names vary by module and by any renaming you’ve done. Use the record ID as your key on the receiving end: names and emails change, IDs don’t. If you create webhooks through Zoho’s API instead of the UI, the merge-field syntax is slightly different (${!Leads.Email}), so don’t copy one into the other. (Create Webhook API)
Include an event value you set yourself (like "contact.created" above). If several workflow rules post to the same URL, it’s the easiest way for the receiving side to tell them apart.
Step 3: Attach It to a Workflow Rule
- Go to Setup > Automation > Workflow Rules and create a rule
- Pick the module and when the rule runs: On a record action. Choose Create, Edit, Create or Edit, Field Update or Delete
- For Edit triggers, decide whether to tick Repeat this workflow every time a record is edited. Leave it unticked and the rule fires only the first time the criteria are met
- Add criteria if only some records should trigger it (for example, only deals in a certain pipeline)
- Under Instant Actions, choose Webhook, select the webhook you created and Associate it
- Save, and confirm the rule is active
A rule can carry up to 6 webhooks (1 instant plus 5 time-based), and each condition can have one instant webhook. Delete-triggered rules can only run email notifications, webhooks and functions, and the record’s data is limited by then, so we capture the ID and handle the rest on our side.
Typical rule set
| Integration need | Rule |
|---|---|
| New contacts to the integration | Contacts, on Create |
| Contact updates | Contacts, on Edit (repeat on every edit) |
| Deal stage changes | Deals, on Field Update (Stage) |
| New deals | Deals, on Create |
| Deleted records | Each module, on Delete |
Limits to Plan Around
These are the ones that bite in production. (Zoho help: webhooks)
- Daily webhook calls by edition (whichever is lower):
- Professional: 50,000 per day or 100 per user per day
- Enterprise: 500,000 per day or 500 per user per day
- Ultimate: 1,000,000 per day or 1,000 per user per day
- 10-second timeout. If your endpoint doesn’t respond within 10 seconds, Zoho records a socket timeout.
- Failures are notified, not guaranteed to be redelivered. Zoho emails a failure notification (and another 15 minutes later). It doesn’t document automatic redelivery of a failed call. Treat a failed webhook as a missed event unless your integration backfills.
- A small team on Professional can hit the per-user cap. 5 users means 500 calls a day. Bulk imports and mass updates burn through that fast.
So the receiving endpoint should respond immediately (store the payload, return 200, process in the background), and the integration should have a way to catch up on anything missed, usually a periodic API query for records modified since the last successful sync.
The Alternative: Zoho’s Notification API
For high-volume modules, or when you want every change rather than rule-filtered ones, Zoho’s Notification API is often a better fit. Instead of workflow rules, the integration subscribes a channel to events like Contacts.create, Contacts.edit, Deals.all, and Zoho posts a notification to the notify_url.
What’s different:
- It tells you what changed, not the full record. The notification includes the module, the operation, the affected record
idsand (optionally) the changed fields. The integration then fetches the details through the API. - Channels expire. The maximum
channel_expiryis one week. If you omit it or ask for longer, Zoho sets one hour. The integration must re-enable channels before they lapse. (Update notification details) - You can set a
token(up to 50 characters) that comes back with every notification, so you can verify the source. - No per-rule setup in the UI. Everything is configured through the API, which is easier to manage across many modules.
We often combine them: workflow webhooks for the few events that need rich, filtered payloads, and the Notification API with API fetches for broad sync.
Testing
- Point the webhook at a request inspector first (webhook.site or similar). Create or edit a test record and inspect exactly what Zoho sends, especially the merge-field values.
- Test each rule’s trigger. An Edit rule won’t fire on create, and an Edit rule without “repeat” only fires the first time the criteria match.
- Test the criteria edges. Use a record that should not trigger the rule and confirm nothing arrives.
- Test a delete if you subscribed to deletes, and check what data survives.
- Switch the URL to production once the payloads look right.
Troubleshooting
Webhook Not Firing
- Is the workflow rule active, and does the record meet its criteria?
- Is it an Edit rule without “Repeat this workflow every time a record is edited”? Then it only fires the first time.
- Have you hit the daily limit? Zoho lists “daily limit reached” as a failure reason. Check usage under Setup > Automation > Actions > Webhooks.
Failure Notifications
Zoho’s failure reasons include bad request, unauthorized, page not found, server unavailable, third-party error and socket timeout. Unauthorized usually means the secret header or token changed. Socket timeout means the endpoint took longer than 10 seconds.
Payload Missing Fields or Showing Placeholders
Edit the webhook and re-insert the field with the # picker. Hand-typed placeholders with the wrong field name won’t resolve. Zoho also limits how many CRM fields a webhook can send to a third-party app (10), so send the ID plus the essentials and fetch the rest through the API.
Events Missed During an Outage
If the endpoint was down, those calls failed and won’t be replayed. Run a catch-up sync: query the API for records modified since the last event you processed.
Next Steps
- Set up API access for the write-back side: Zoho CRM API Setup
- General webhook debugging: Common Webhook Issues
- Rather we handle it? CRM Integration Services