Webhooks & Zapier Integration
ISAO API provides powerful webhook functionality for real-time notifications and seamless integration with automation platforms like Zapier, Make.com, and custom applications.
📋 Table of Contents
- Overview
- Zapier Integration
- Webhook Events
- REST Hooks
- Event Samples
- Zapier App Development
- Make.com Integration
- Custom Webhooks
- Troubleshooting
🔔 Overview
ISAO supports REST Hooks (reverse webhooks) that allow external applications to subscribe to real-time events. When events occur in your ISAO system, webhook notifications are sent automatically to your configured endpoints.
Supported Platforms
- Zapier: Connect 6000+ apps with automated workflows
- Make.com: Advanced scenario automation
- Custom Applications: Build your own integrations
- n8n: Self-hosted automation alternative
Authentication
All webhook endpoints require the webhooks:read or webhooks:write permissions:
Authorization: Bearer YOUR_API_KEY
⚡ Zapier Integration
Quick Setup
- Create a Zapier account at zapier.com
- Generate an API key with
webhooks:writepermission - Create a Zap using ISAO as a trigger app
- Configure your action in another app
Zapier Trigger Setup
// Example Zapier trigger configuration
const triggerConfig = {
"key": "new_contact",
"noun": "Contact",
"display": {
"label": "New Contact",
"description": "Triggers when a new contact is added to ISAO."
},
"operation": {
"type": "hook",
"performSubscribe": {
"url": "https://staging.isao.io/api/external/webhooks/subscribe",
"method": "POST",
"headers": {
"Authorization": "Bearer {{bundle.authData.api_key}}"
},
"body": {
"event": "contact.created",
"target_url": "{{bundle.targetUrl}}"
}
},
"performUnsubscribe": {
"url": "https://staging.isao.io/api/external/webhooks/unsubscribe",
"method": "DELETE",
"headers": {
"Authorization": "Bearer {{bundle.authData.api_key}}"
},
"body": {
"subscription_id": "{{bundle.subscribeData.subscription_id}}"
}
},
"performList": {
"url": "https://staging.isao.io/api/external/triggers/contact.created/recent",
"method": "GET",
"headers": {
"Authorization": "Bearer {{bundle.authData.api_key}}"
}
}
}
}
📡 Webhook Events
Available Event Types
| Event | Description | Trigger Condition |
|---|---|---|
contact.created | New contact added | When a contact is created via API or UI |
contact.updated | Contact information changed | When contact data is modified |
deal.created | New deal added | When a deal is created |
deal.updated | Deal information changed | When deal data is modified |
deal.stage_changed | Deal moved to new stage | When deal stage is updated |
deal.won | Deal marked as won | When deal status changes to "won" |
deal.lost | Deal marked as lost | When deal status changes to "lost" |
Event Payload Structure
All webhook events follow this structure:
{
"event": "contact.created",
"timestamp": "2024-11-08T10:30:00.000Z",
"data": {
// Event-specific data (contact, deal, etc.)
},
"metadata": {
"companyId": "cmb72clgt0003145mvfrg8iyh",
"eventId": "event_12345",
"source": "api"
}
}
🔗 REST Hooks
Subscribe to Webhooks
Create a new webhook subscription for real-time notifications.
Request
POST /webhooks/subscribe
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
event | string | ✅ | Event type to subscribe to |
target_url | string | ✅ | Your webhook endpoint URL |
filters | object | ❌ | Optional event filters |
Example Request
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": "contact.created",
"target_url": "https://hooks.zapier.com/hooks/catch/12345/abcdef",
"filters": {
"tags": ["lead", "enterprise"]
}
}' \
https://staging.isao.io/api/external/webhooks/subscribe
Response
{
"success": true,
"data": {
"id": "hook_789",
"subscription_id": "sub_abc123",
"event": "contact.created",
"target_url": "https://hooks.zapier.com/hooks/catch/12345/abcdef",
"created_at": "2024-11-08T10:30:00.000Z"
}
}
Unsubscribe from Webhooks
Remove an existing webhook subscription.
Request
DELETE /webhooks/unsubscribe
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
Example Request
curl -X DELETE \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subscription_id": "sub_abc123"
}' \
https://staging.isao.io/api/external/webhooks/unsubscribe
Response
{
"success": true,
"message": "Webhook unsubscribed successfully"
}
List Active Webhooks
Retrieve all active webhook subscriptions for your company.
Request
GET /webhooks
Authorization: Bearer YOUR_API_KEY
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://staging.isao.io/api/external/webhooks
Response
{
"success": true,
"data": [
{
"id": "hook_789",
"subscription_id": "sub_abc123",
"event_type": "contact.created",
"target_url": "https://hooks.zapier.com/hooks/catch/12345/abcdef",
"is_active": true,
"created_at": "2024-11-08T10:30:00.000Z"
}
]
}
📄 Event Samples
Get Sample Data
Retrieve sample event data for testing and development.
Request
GET /triggers/:event_type/sample
Authorization: Bearer YOUR_API_KEY
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://staging.isao.io/api/external/triggers/contact.created/sample
Response
{
"id": "contact_sample",
"name": "John Doe",
"firstName": "John",
"lastName": "Doe",
"phoneNumber": "+33123456789",
"email": "john.doe@example.com",
"position": "CEO",
"currentCompany": "Tech Corp",
"industrySector": "Technology",
"city": "Paris",
"country": "France",
"tags": ["vip", "enterprise"],
"createdAt": "2024-11-08T10:30:00.000Z",
"updatedAt": "2024-11-08T10:30:00.000Z"
}
Get Recent Data
Retrieve recent real data for polling-based integrations.
Request
GET /triggers/:event_type/recent?limit=100&since=2024-11-01T00:00:00.000Z
Authorization: Bearer YOUR_API_KEY
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/triggers/contact.created/recent?limit=10"
Response
[
{
"id": "contact_123",
"name": "Jane Smith",
"firstName": "Jane",
"lastName": "Smith",
"phoneNumber": "+33987654321",
"email": "jane@example.com",
"createdAt": "2024-11-08T09:30:00.000Z",
"updatedAt": "2024-11-08T09:30:00.000Z"
}
]
🔧 Zapier App Development
Authentication Configuration
// authentication.js
module.exports = {
type: 'custom',
fields: [
{
computed: false,
key: 'api_key',
required: true,
label: 'API Key',
type: 'password',
helpText: 'Your ISAO API key from the dashboard'
}
],
test: {
url: 'https://staging.isao.io/api/external/test',
method: 'GET',
headers: {
'Authorization': 'Bearer {{bundle.authData.api_key}}'
}
},
connectionLabel: 'Connected to ISAO ({{bundle.authData.company_name}})'
};
Trigger Definition
// triggers/new_contact.js
const perform = (z, bundle) => {
// Return recent contacts for initial poll
const options = {
url: 'https://staging.isao.io/api/external/triggers/contact.created/recent',
method: 'GET',
headers: {
'Authorization': `Bearer ${bundle.authData.api_key}`
},
params: {
limit: bundle.meta.limit || 100
}
};
return z.request(options).then((response) => {
return response.json;
});
};
const performSubscribe = (z, bundle) => {
// Subscribe to webhook
const options = {
url: 'https://staging.isao.io/api/external/webhooks/subscribe',
method: 'POST',
headers: {
'Authorization': `Bearer ${bundle.authData.api_key}`,
'Content-Type': 'application/json'
},
body: {
event: 'contact.created',
target_url: bundle.targetUrl
}
};
return z.request(options).then((response) => {
return response.json.data;
});
};
const performUnsubscribe = (z, bundle) => {
// Unsubscribe from webhook
const options = {
url: 'https://staging.isao.io/api/external/webhooks/unsubscribe',
method: 'DELETE',
headers: {
'Authorization': `Bearer ${bundle.authData.api_key}`,
'Content-Type': 'application/json'
},
body: {
subscription_id: bundle.subscribeData.subscription_id
}
};
return z.request(options);
};
module.exports = {
key: 'new_contact',
noun: 'Contact',
display: {
label: 'New Contact',
description: 'Triggers when a new contact is added to ISAO.'
},
operation: {
type: 'hook',
performSubscribe,
performUnsubscribe,
perform,
sample: {
id: 'contact_123',
name: 'John Doe',
email: 'john@example.com',
phoneNumber: '+33123456789'
}
}
};
Action Definition
// creates/create_contact.js
const perform = (z, bundle) => {
const options = {
url: 'https://staging.isao.io/api/external/contacts',
method: 'POST',
headers: {
'Authorization': `Bearer ${bundle.authData.api_key}`,
'Content-Type': 'application/json'
},
body: {
name: bundle.inputData.name,
phoneNumber: bundle.inputData.phoneNumber,
email: bundle.inputData.email,
position: bundle.inputData.position,
currentCompany: bundle.inputData.currentCompany,
tags: bundle.inputData.tags ? bundle.inputData.tags.split(',') : []
}
};
return z.request(options).then((response) => {
return response.json.data;
});
};
module.exports = {
key: 'create_contact',
noun: 'Contact',
display: {
label: 'Create Contact',
description: 'Creates a new contact in ISAO.'
},
operation: {
inputFields: [
{
key: 'name',
label: 'Name',
type: 'string',
required: true
},
{
key: 'phoneNumber',
label: 'Phone Number',
type: 'string',
required: true
},
{
key: 'email',
label: 'Email',
type: 'string',
required: false
},
{
key: 'position',
label: 'Position',
type: 'string',
required: false
},
{
key: 'currentCompany',
label: 'Company',
type: 'string',
required: false
},
{
key: 'tags',
label: 'Tags',
type: 'string',
helpText: 'Comma-separated list of tags',
required: false
}
],
perform,
sample: {
id: 'contact_123',
name: 'John Doe',
email: 'john@example.com'
}
}
};
🔄 Make.com Integration
HTTP Module Configuration
{
"url": "https://staging.isao.io/api/external/contacts",
"method": "POST",
"headers": {
"Authorization": "Bearer {{your_api_key}}",
"Content-Type": "application/json"
},
"body": {
"name": "{{contact.name}}",
"phoneNumber": "{{contact.phone}}",
"email": "{{contact.email}}"
}
}
Webhook Module Setup
- Add Webhook trigger in your Make scenario
- Copy the webhook URL provided by Make
- Subscribe to ISAO events using the webhook URL:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": "contact.created",
"target_url": "https://hook.eu1.make.com/12345abcdef"
}' \
https://staging.isao.io/api/external/webhooks/subscribe
🛠️ Custom Webhooks
Node.js Webhook Receiver
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Webhook endpoint
app.post('/webhook/isao', (req, res) => {
const event = req.body;
console.log('Received event:', event.event);
console.log('Event data:', event.data);
// Process the event based on type
switch (event.event) {
case 'contact.created':
handleNewContact(event.data);
break;
case 'deal.won':
handleDealWon(event.data);
break;
default:
console.log('Unknown event type:', event.event);
}
// Respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});
function handleNewContact(contact) {
console.log('New contact:', contact.name);
// Add your business logic here
// e.g., send welcome email, add to CRM, etc.
}
function handleDealWon(deal) {
console.log('Deal won:', deal.title, deal.value);
// Add your business logic here
// e.g., generate invoice, send congratulations, etc.
}
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
Python Flask Webhook Receiver
from flask import Flask, request, jsonify
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
@app.route('/webhook/isao', methods=['POST'])
def handle_webhook():
event_data = request.json
event_type = event_data.get('event')
data = event_data.get('data', {})
logging.info(f"Received event: {event_type}")
if event_type == 'contact.created':
handle_new_contact(data)
elif event_type == 'deal.won':
handle_deal_won(data)
else:
logging.warning(f"Unknown event type: {event_type}")
return jsonify({'received': True}), 200
def handle_new_contact(contact):
logging.info(f"New contact: {contact.get('name')}")
# Add your business logic here
def handle_deal_won(deal):
logging.info(f"Deal won: {deal.get('title')} - {deal.get('value')}")
# Add your business logic here
if __name__ == '__main__':
app.run(debug=True, port=3000)
🔍 Troubleshooting
Common Issues
1. Webhook Not Receiving Events
Check:
- Webhook URL is publicly accessible (use ngrok for local testing)
- API key has
webhooks:writepermission - Subscription is active (check with
GET /webhooks) - Webhook endpoint responds with 200 status
Debug:
# Test webhook endpoint manually
curl -X POST \
-H "Content-Type: application/json" \
-d '{"event":"test","data":{"test":true}}' \
https://your-webhook-url.com/webhook
2. Zapier Trigger Not Working
Check:
- API key is correctly entered in Zapier
- Trigger is properly subscribed
- Sample data is available
Debug:
# Check recent trigger data
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/triggers/contact.created/recent?limit=1"
3. Event Payload Issues
Common problems:
- Missing required fields in webhook payload
- Incorrect date format expectations
- Nested object access in automation tools
Solution: Use the sample endpoints to understand exact payload structure:
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://staging.isao.io/api/external/triggers/contact.created/sample
Testing Webhooks Locally
Using ngrok
- Install ngrok: ngrok.com
- Start your local server on port 3000
- Expose with ngrok:
ngrok http 3000 - Use the ngrok URL for webhook subscription:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": "contact.created",
"target_url": "https://abc123.ngrok.io/webhook/isao"
}' \
https://staging.isao.io/api/external/webhooks/subscribe
Webhook Testing Tools
- RequestBin: requestbin.com
- Webhook.site: webhook.site
- Postman Mock Server: For testing webhook payloads
Event Delivery Guarantees
- Retry Policy: Failed webhooks are retried up to 3 times
- Timeout: Webhooks timeout after 30 seconds
- Order: Events are delivered in the order they occur
- Deduplication: Each event has a unique
eventIdfor deduplication
📈 Best Practices
- Respond quickly: Always respond with 200 status within 30 seconds
- Handle duplicates: Use
eventIdfor idempotent processing - Verify signatures: Implement signature verification for security
- Use HTTPS: Always use HTTPS endpoints for webhooks
- Log events: Keep logs of received events for debugging
- Graceful degradation: Handle missing or unexpected fields
- Test thoroughly: Use sample data to test your integration
- Monitor health: Set up alerts for webhook failures
🔗 Related Documentation
- Authentication - API key setup for webhooks
- Contacts API - Understanding contact events
- Deals API - Understanding deal events
- Error Handling - Webhook error responses