Zoho CRM Integration
Automate SMS notifications for your sales and customer relationship management workflows. Send personalized messages when leads are created, deals are updated, or appointments are scheduled.
Use Case: Automatically notify leads and customers via SMS when important events occur in your Zoho CRM.
How It Works
Zoho CRM can trigger SMS notifications through webhook workflows when:
- New leads are created
- Deals move through pipeline stages
- Appointments are scheduled or updated
- Tasks are assigned to team members
- Custom field values change
- Follow-up reminders are due
Prerequisites
Before you begin, ensure you have:
- An active SMSLeopard account with API credentials (Get started here)
- Zoho CRM account with workflow automation access
- A webhook endpoint to receive Zoho notifications
Integration Steps
Step 1: Set Up Webhook Endpoint
Create an endpoint to receive webhooks from Zoho CRM:
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
// Zoho CRM webhook endpoint
app.post('/zoho/webhook', async (req, res) => {
try {
const { module, action, data } = req.body;
console.log('Zoho webhook received:', { module, action });
// Handle different modules and actions
if (module === 'Leads' && action === 'create') {
await handleNewLead(data);
} else if (module === 'Deals' && action === 'update') {
await handleDealUpdate(data);
} else if (module === 'Events' && action === 'create') {
await handleAppointment(data);
}
res.json({ success: true, message: 'Webhook processed' });
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
// Handle new lead
async function handleNewLead(lead) {
const phoneNumber = lead.Phone || lead.Mobile;
const firstName = lead.First_Name;
const lastName = lead.Last_Name;
if (!phoneNumber) {
console.log('No phone number found for lead');
return;
}
const message = `Hi ${firstName}, thank you for your interest! Our team will contact you shortly to discuss how we can help.`;
await sendSMS(phoneNumber, message);
}
// Handle deal stage update
async function handleDealUpdate(deal) {
if (deal.Stage === 'Closed Won') {
const contactPhone = deal.Contact_Phone || deal.Contact_Mobile;
const dealName = deal.Deal_Name;
const amount = deal.Amount;
if (contactPhone) {
const message = `Congratulations! Your deal "${dealName}" worth $${amount} has been confirmed. We're excited to work with you!`;
await sendSMS(contactPhone, message);
}
}
}
// Handle appointment
async function handleAppointment(event) {
const attendeePhone = event.Participant_Phone;
const eventTitle = event.Event_Title;
const startTime = new Date(event.Start_DateTime);
if (attendeePhone) {
const formattedTime = startTime.toLocaleString('en-US', {
dateStyle: 'medium',
timeStyle: 'short'
});
const message = `Appointment confirmed: ${eventTitle} on ${formattedTime}. We look forward to meeting you!`;
await sendSMS(attendeePhone, message);
}
}
// Send SMS using SMSLeopard API
async function sendSMS(phoneNumber, message) {
const apiKey = process.env.SMSLEOPARD_API_KEY;
const apiSecret = process.env.SMSLEOPARD_API_SECRET;
const sourceAddress = process.env.SENDER_ID;
const formattedPhone = formatPhoneNumber(phoneNumber);
try {
const response = await axios.post(
'https://api.smsleopard.com/v1/sms/send',
{
source: sourceAddress,
destination: [formattedPhone],
message: message
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}:${apiSecret}`
}
}
);
console.log('SMS sent successfully:', response.data);
return response.data;
} catch (error) {
console.error('Error sending SMS:', error.response?.data || error.message);
throw error;
}
}
function formatPhoneNumber(phone) {
// Remove spaces and special characters
phone = phone.replace(/[\s\-\(\)]/g, '');
// Add country code if missing (example for Kenya)
if (phone.startsWith('0')) {
return '254' + phone.substring(1);
} else if (phone.startsWith('+')) {
return phone.substring(1);
}
return phone;
}
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Zoho webhook server running on port ${PORT}`);
});
Step 2: Configure Zoho CRM Webhook
- Log in to Zoho CRM and navigate to Setup > Automation > Workflows
- Click Create Rule and select the module (Leads, Deals, Events, etc.)
- Set up your trigger conditions (e.g., "When a record is created")
- Add a Webhook action:
- URL: Your webhook endpoint (e.g.,
https://yourdomain.com/zoho/webhook) - Method: POST
- Format: JSON
- URL: Your webhook endpoint (e.g.,
- Map the fields you want to send to your webhook
Step 3: Test Your Integration
Create a test record in Zoho CRM to verify the webhook triggers and SMS sends correctly.
Use Cases
Lead Nurturing
Send immediate follow-up messages to new leads:
const leadTemplates = {
newLead: (name) =>
`Hi ${name}, thanks for reaching out! We've received your inquiry and will get back to you within 24 hours.`,
leadQualified: (name, product) =>
`Hi ${name}, great news! You qualify for our ${product}. Our sales team will call you today.`,
followUp: (name, days) =>
`Hi ${name}, just checking in! It's been ${days} days since we last spoke. Any questions we can answer?`
};Deal Stage Notifications
Keep customers informed as deals progress:
const dealTemplates = {
proposal: (name, dealName) =>
`Hi ${name}, your proposal for "${dealName}" is ready for review. Check your email for details.`,
negotiation: (name) =>
`Hi ${name}, we're reviewing your requirements and will send you a revised offer shortly.`,
won: (name, amount) =>
`Congratulations ${name}! Your deal worth $${amount} is confirmed. Welcome aboard!`,
lost: (name) =>
`Hi ${name}, we appreciate you considering us. We'd love to work with you in the future!`,
};Appointment Reminders
Send reminders before scheduled meetings:
const cron = require('node-cron');
// Send reminders 24 hours before appointments
cron.schedule('0 9 \* \* \*', async () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
// Fetch appointments from Zoho CRM API
const appointments = await fetchTomorrowAppointments(tomorrow);
for (const appointment of appointments) {
const message = `Reminder: You have an appointment tomorrow at ${appointment.time} for ${appointment.title}. See you then!`;
await sendSMS(appointment.phone, message);
}
});
async function fetchTomorrowAppointments(date) {
// Implement Zoho CRM API call to fetch appointments
// This is a placeholder - actual implementation depends on Zoho API
return [];
}
Advanced Features
Custom Field Triggers
Send SMS based on custom field changes:
app.post('/zoho/webhook', async (req, res) => {
const { data, previous_data } = req.body;
// Check if payment status changed to "Paid"
if (data.Payment_Status === 'Paid' && previous_data.Payment_Status !== 'Paid') {
const message = `Payment received! Your invoice #${data.Invoice_Number} has been marked as paid. Thank you!`;
await sendSMS(data.Contact_Phone, message);
}
res.json({ success: true });
});Multi-language Support
Send messages in the customer's preferred language:
const messages = {
en: {
welcome: (name) => `Hi ${name}, welcome! We're excited to work with you.`,
appointment: (time) => `Appointment confirmed for ${time}. See you then!`,
},
sw: {
welcome: (name) =>
`Habari ${name}, karibu! Tunafurahi kufanya kazi na wewe.`,
appointment: (time) => `Miadi imethibitishwa kwa ${time}. Tutaonana!`,
},
};
function getLocalizedMessage(language, key, ...args) {
const template = messages[language]?.[key] || messages.en[key];
return template(...args);
}Best Practices
- Always validate webhook authenticity using Zoho's webhook validation tokens
- Store phone numbers in E.164 format in Zoho CRM for consistency
- Implement retry logic for failed SMS sends
- Log all webhook events for debugging and audit purposes
- Use custom fields in Zoho to store SMS delivery status
- Respect opt-out preferences stored in your CRM
- Test with staging environment before going live
Monitoring
Track your integration performance:
// Log webhook events to database
async function logWebhookEvent(module, action, recordId, status) {
await db.webhookLogs.create({
module,
action,
recordId,
status,
timestamp: new Date(),
});
}
// Track SMS delivery
async function trackSMSDelivery(phone, message, response) {
await db.smsLogs.create({
phone,
message,
deliveryStatus: response.status,
messageId: response.messageId,
timestamp: new Date(),
});
}Refer to Zoho CRM Webhook Documentation (opens in a new tab) for more information.