Webhook Configuration To set up webhooks for your integration, visit the Unizo Console Webhooks section for step-by-step configuration guide.
Overview
Unizo's Communications API provides webhooks to notify your application when important communication events occur across your integrated platforms. These real-time notifications enable you to build responsive applications that react immediately to message activity, channel updates, and user interactions.
Our platform normalizes webhook events from various communication providers (Slack, Microsoft Teams, Discord, etc.) into a consistent format, making it easy to handle events regardless of the underlying platform.
Supported Event Types
Event Type Description Trigger Conditions Triggered when a new message is sent Triggered when a message is edited or updated Triggered when a message is deleted Triggered when a new channel or conversation is created Triggered when channel properties are modified Triggered when a channel is archived Triggered when a user joins a channel Triggered when a user leaves a channel Triggered when a reaction is added to a message Triggered when a reaction is removed from a message
Webhook Security All webhooks from Unizo include security headers to verify authenticity:
Headers Header Description x-unizo-event-typeThe type of event that triggered the webhook x-unizo-signatureHMAC SHA-256 signature for request validation x-unizo-timestampUnix timestamp when the event was sent x-unizo-delivery-idUnique identifier for this webhook delivery
Signature Verification Verify the authenticity of incoming webhooks using HMAC SHA-256:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
Event Details
Message Events
Triggered when a new message is posted in any channel or direct message conversation across your connected communication platforms.
Headers Name Type Required Description Content-Typestring Yes Always application/json x-unizo-event-typestring Yes Event type: message:sent x-unizo-webhook-idstring Yes Unique webhook configuration ID x-unizo-delivery-idstring Yes Unique delivery attempt ID x-unizo-signaturestring Yes HMAC SHA256 signature for verification
Request Body Schema Property Type Required Description typestring Yes Event type identifier versionstring Yes Webhook payload version data.message.idstring Yes Unique message identifier data.message.contentstring Yes Message text content data.message.channel_idstring Yes Channel where message was sent data.message.author.idstring Yes Author's user ID data.message.author.namestring Yes Author's display name data.message.author.emailstring No Author's email address data.message.timestampstring Yes Message creation time (ISO 8601) data.message.attachmentsarray No Message attachments data.message.mentionsarray No Users or channels mentioned integration.idstring Yes Integration ID integration.namestring Yes Integration name integration.providerstring Yes Provider name (e.g., slack, teams)
Example Payload Copy {
"type" : "message:sent" ,
"version" : "1.0.0" ,
"data" : {
"message" : {
"id" : "msg_abc123" ,
"content" : "Hello team! Just pushed the latest updates to production." ,
"channel_id" : "ch_general" ,
"author" : {
"id" : "usr_123456" ,
"name" : "Jane Smith" ,
"email" : "jane.smith@company.com"
} ,
"timestamp" : "2024-06-15T14:30:00Z" ,
"attachments" : [ ] ,
"mentions" : [ ]
}
} ,
"integration" : {
"id" : "int_slack_789" ,
"name" : "Company Slack" ,
"provider" : "slack"
}
}
Response 200 OKWebhook processed successfully 400 Bad RequestInvalid webhook payload 401 UnauthorizedInvalid or missing signature
Triggered when an existing message is edited or updated in any connected communication platform.
Headers Name Type Required Description Content-Typestring Yes Always application/json x-unizo-event-typestring Yes Event type: message:updated x-unizo-webhook-idstring Yes Unique webhook configuration ID x-unizo-delivery-idstring Yes Unique delivery attempt ID x-unizo-signaturestring Yes HMAC SHA256 signature for verification
Request Body Schema Property Type Required Description typestring Yes Event type identifier versionstring Yes Webhook payload version data.message.idstring Yes Unique message identifier data.message.contentstring Yes Updated message content data.message.previous_contentstring No Previous message content data.message.channel_idstring Yes Channel ID data.message.edited_atstring Yes Edit timestamp (ISO 8601) data.message.edited_by.idstring Yes Editor's user ID data.message.edited_by.namestring Yes Editor's display name integration.idstring Yes Integration ID integration.namestring Yes Integration name integration.providerstring Yes Provider name
Example Payload Copy {
"type" : "message:updated" ,
"version" : "1.0.0" ,
"data" : {
"message" : {
"id" : "msg_abc123" ,
"content" : "Hello team! Just pushed the latest updates to production. ✅" ,
"previous_content" : "Hello team! Just pushed the latest updates to production." ,
"channel_id" : "ch_general" ,
"edited_at" : "2024-06-15T14:35:00Z" ,
"edited_by" : {
"id" : "usr_123456" ,
"name" : "Jane Smith"
}
}
} ,
"integration" : {
"id" : "int_slack_789" ,
"name" : "Company Slack" ,
"provider" : "slack"
}
}
Response 200 OKWebhook processed successfully 400 Bad RequestInvalid webhook payload 401 UnauthorizedInvalid or missing signature
Channel Events
Triggered when a new channel or conversation is created in your connected communication platforms.
Headers Name Type Required Description Content-Typestring Yes Always application/json x-unizo-event-typestring Yes Event type: channel:created x-unizo-webhook-idstring Yes Unique webhook configuration ID x-unizo-delivery-idstring Yes Unique delivery attempt ID x-unizo-signaturestring Yes HMAC SHA256 signature for verification
Request Body Schema Property Type Required Description typestring Yes Event type identifier versionstring Yes Webhook payload version data.channel.idstring Yes Unique channel identifier data.channel.namestring Yes Channel name data.channel.descriptionstring No Channel description data.channel.typestring Yes Channel type (public, private, direct) data.channel.created_by.idstring Yes Creator's user ID data.channel.created_by.namestring Yes Creator's display name data.channel.created_atstring Yes Creation timestamp (ISO 8601) data.channel.member_countinteger No Initial member count integration.idstring Yes Integration ID integration.namestring Yes Integration name integration.providerstring Yes Provider name
Example Payload Copy {
"type" : "channel:created" ,
"version" : "1.0.0" ,
"data" : {
"channel" : {
"id" : "ch_project_alpha" ,
"name" : "project-alpha" ,
"description" : "Discussion channel for Project Alpha development" ,
"type" : "public" ,
"created_by" : {
"id" : "usr_789012" ,
"name" : "John Doe"
} ,
"created_at" : "2024-06-15T10:00:00Z" ,
"member_count" : 5
}
} ,
"integration" : {
"id" : "int_teams_456" ,
"name" : "Company Teams" ,
"provider" : "microsoft_teams"
}
}
Response 200 OKWebhook processed successfully 400 Bad RequestInvalid webhook payload 401 UnauthorizedInvalid or missing signature
Member Events
Triggered when a user joins a channel or is added to a conversation.
Headers Name Type Required Description Content-Typestring Yes Always application/json x-unizo-event-typestring Yes Event type: member:joined x-unizo-webhook-idstring Yes Unique webhook configuration ID x-unizo-delivery-idstring Yes Unique delivery attempt ID x-unizo-signaturestring Yes HMAC SHA256 signature for verification
Request Body Schema Property Type Required Description typestring Yes Event type identifier versionstring Yes Webhook payload version data.channel_idstring Yes Channel ID data.channel_namestring Yes Channel name data.member.idstring Yes User ID data.member.namestring Yes User display name data.member.emailstring No User email data.invited_by.idstring No Inviter's user ID data.invited_by.namestring No Inviter's display name data.joined_atstring Yes Join timestamp (ISO 8601) integration.idstring Yes Integration ID integration.namestring Yes Integration name integration.providerstring Yes Provider name
Example Payload Copy {
"type" : "member:joined" ,
"version" : "1.0.0" ,
"data" : {
"channel_id" : "ch_project_alpha" ,
"channel_name" : "project-alpha" ,
"member" : {
"id" : "usr_345678" ,
"name" : "Sarah Johnson" ,
"email" : "sarah.johnson@company.com"
} ,
"invited_by" : {
"id" : "usr_789012" ,
"name" : "John Doe"
} ,
"joined_at" : "2024-06-15T11:30:00Z"
} ,
"integration" : {
"id" : "int_slack_789" ,
"name" : "Company Slack" ,
"provider" : "slack"
}
}
Response 200 OKWebhook processed successfully 400 Bad RequestInvalid webhook payload 401 UnauthorizedInvalid or missing signature
Webhook Delivery & Retries
Unizo implements a robust delivery system with automatic retries to ensure your webhooks are delivered reliably:
Timeout : 30 seconds per delivery attempt
Retry Schedule : 5 attempts with exponential backoff
Attempt 1: Immediate
Attempt 2: 1 minute delay
Attempt 3: 5 minutes delay
Attempt 4: 30 minutes delay
Attempt 5: 2 hours delay
Success Criteria : HTTP status codes 200-299
Failure Handling : After 5 failed attempts, the webhook is marked as failed
Best Practices
1. Idempotency
Always implement idempotent webhook handlers using the x-unizo-delivery-id header:
Idempotent Webhook Handler // Example: Handling webhooks idempotently
app.post('/webhooks/communications', async (req, res) => {
const deliveryId = req.headers['x-unizo-delivery-id'];
// Check if we've already processed this delivery
const existingDelivery = await db.webhookDeliveries.findOne({
deliveryId
});
if (existingDelivery) {
console.log(`Duplicate delivery detected: ${deliveryId}`);
return res.status(200).json({
status: 'already_processed'
});
}
// Process the webhook
try {
await processWebhook(req.body);
// Record the delivery
await db.webhookDeliveries.create({
deliveryId,
processedAt: new Date()
});
res.status(200).json({ status: 'success' });
} catch (error) {
console.error('Webhook processing failed:', error);
res.status(500).json({ status: 'error' });
}
});
2. Async Processing
For better performance and reliability, process webhooks asynchronously:
Async Webhook Processing // Example: Queue webhooks for async processing
app.post('/webhooks/communications', async (req, res) => {
const { type, data } = req.body;
// Immediately acknowledge receipt
res.status(200).json({ status: 'received' });
// Queue for async processing
await messageQueue.publish('webhook.communications', {
type,
data,
headers: {
webhookId: req.headers['x-unizo-webhook-id'],
deliveryId: req.headers['x-unizo-delivery-id'],
signature: req.headers['x-unizo-signature']
},
receivedAt: new Date()
});
});
// Background worker
messageQueue.subscribe('webhook.communications', async (message) => {
const { type, data } = message;
switch (type) {
case 'message:sent':
await handleNewMessage(data.message);
break;
case 'channel:created':
await handleNewChannel(data.channel);
break;
// ... other event types
}
});
3. Error Handling
Implement comprehensive error handling and monitoring:
Error Handling // Example: Robust error handling
app.post('/webhooks/communications', async (req, res) => {
try {
// Validate webhook signature
if (!validateWebhookSignature(req)) {
return res.status(401).json({
error: 'Invalid signature'
});
}
// Validate payload structure
const { error } = validateWebhookPayload(req.body);
if (error) {
return res.status(400).json({
error: 'Invalid payload',
details: error.details
});
}
// Process webhook
await processWebhook(req.body);
res.status(200).json({ status: 'success' });
} catch (error) {
// Log error with context
logger.error('Webhook processing failed', {
error: error.message,
stack: error.stack,
webhookType: req.body.type,
integrationId: req.body.integration?.id,
deliveryId: req.headers['x-unizo-delivery-id']
});
// Return 500 to trigger retry
res.status(500).json({
error: 'Internal server error'
});
}
});
Need Help?
For webhook-related support: