Communications Webhooks
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-type | The type of event that triggered the webhook |
x-unizo-signature | HMAC SHA-256 signature for request validation |
x-unizo-timestamp | Unix timestamp when the event was sent |
x-unizo-delivery-id | Unique 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
Message Sent
message:sent
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
Content-Type | string | Yes | Always application/json |
x-unizo-event-type | string | Yes | Event type: message:sent |
x-unizo-webhook-id | string | Yes | Unique webhook configuration ID |
x-unizo-delivery-id | string | Yes | Unique delivery attempt ID |
x-unizo-signature | string | Yes | HMAC SHA256 signature for verification |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
data.message.id | string | Yes | Unique message identifier |
data.message.content | string | Yes | Message text content |
data.message.channel_id | string | Yes | Channel where message was sent |
data.message.author.id | string | Yes | Author's user ID |
data.message.author.name | string | Yes | Author's display name |
data.message.author.email | string | No | Author's email address |
data.message.timestamp | string | Yes | Message creation time (ISO 8601) |
data.message.attachments | array | No | Message attachments |
data.message.mentions | array | No | Users or channels mentioned |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration name |
integration.provider | string | Yes | Provider name (e.g., slack, teams) |
Example Payload
{"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 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid or missing signature |
Message Updated
message:updated
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
Content-Type | string | Yes | Always application/json |
x-unizo-event-type | string | Yes | Event type: message:updated |
x-unizo-webhook-id | string | Yes | Unique webhook configuration ID |
x-unizo-delivery-id | string | Yes | Unique delivery attempt ID |
x-unizo-signature | string | Yes | HMAC SHA256 signature for verification |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
data.message.id | string | Yes | Unique message identifier |
data.message.content | string | Yes | Updated message content |
data.message.previous_content | string | No | Previous message content |
data.message.channel_id | string | Yes | Channel ID |
data.message.edited_at | string | Yes | Edit timestamp (ISO 8601) |
data.message.edited_by.id | string | Yes | Editor's user ID |
data.message.edited_by.name | string | Yes | Editor's display name |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration name |
integration.provider | string | Yes | Provider name |
Example Payload
{"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 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid or missing signature |
Channel Events
Channel Created
channel:created
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
Content-Type | string | Yes | Always application/json |
x-unizo-event-type | string | Yes | Event type: channel:created |
x-unizo-webhook-id | string | Yes | Unique webhook configuration ID |
x-unizo-delivery-id | string | Yes | Unique delivery attempt ID |
x-unizo-signature | string | Yes | HMAC SHA256 signature for verification |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
data.channel.id | string | Yes | Unique channel identifier |
data.channel.name | string | Yes | Channel name |
data.channel.description | string | No | Channel description |
data.channel.type | string | Yes | Channel type (public, private, direct) |
data.channel.created_by.id | string | Yes | Creator's user ID |
data.channel.created_by.name | string | Yes | Creator's display name |
data.channel.created_at | string | Yes | Creation timestamp (ISO 8601) |
data.channel.member_count | integer | No | Initial member count |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration name |
integration.provider | string | Yes | Provider name |
Example Payload
{"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 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid or missing signature |
Member Events
Member Joined
member:joined
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
Content-Type | string | Yes | Always application/json |
x-unizo-event-type | string | Yes | Event type: member:joined |
x-unizo-webhook-id | string | Yes | Unique webhook configuration ID |
x-unizo-delivery-id | string | Yes | Unique delivery attempt ID |
x-unizo-signature | string | Yes | HMAC SHA256 signature for verification |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
data.channel_id | string | Yes | Channel ID |
data.channel_name | string | Yes | Channel name |
data.member.id | string | Yes | User ID |
data.member.name | string | Yes | User display name |
data.member.email | string | No | User email |
data.invited_by.id | string | No | Inviter's user ID |
data.invited_by.name | string | No | Inviter's display name |
data.joined_at | string | Yes | Join timestamp (ISO 8601) |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration name |
integration.provider | string | Yes | Provider name |
Example Payload
{"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 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid 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:
- Contact support at support@unizo.ai