Skip to main content

Webhooks

Receive real-time notifications when events occur in your connected integrations. Unizo standardizes webhook events across all platforms, giving you a consistent interface for GitHub, GitLab, Jira, ServiceNow, and more.

How Unizo Webhooks Work

Unlike traditional webhooks where you need to register endpoints with each platform individually, Unizo provides:

  1. Single Endpoint Registration: Register once with Unizo, receive events from all integrations
  2. Normalized Events: Consistent event schema regardless of the source platform
  3. Unified Authentication: Use your Unizo API key instead of managing multiple webhook secrets
  4. Cross-Platform Events: Correlate events across different tools (e.g., link GitHub commits to Jira tickets)

Setting Up Webhooks

Step 1: Create a Webhook Endpoint in Unizo Console

  1. Navigate to Unizo Console
  2. Click "Create Webhook Endpoint"
  3. Configure your endpoint:
    • URL: Your application's webhook receiver URL
    • Events: Select specific events or use * for all events
    • Integrations: Choose which integrations to receive events from

Step 2: Configure Your Webhook Receiver

Create an endpoint in your application to receive webhook events:

// Express.js example
const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

// Webhook endpoint
app.post('/webhooks/unizo', async (req, res) => {
const signature = req.headers['x-unizo-signature'];
const timestamp = req.headers['x-unizo-timestamp'];

// Verify webhook authenticity
if (!verifyWebhook(req.body, signature, timestamp)) {
return res.status(401).send('Unauthorized');
}

// Process the event
const event = req.body;
console.log(`Received ${event.type} event from ${event.integration.name}`);

// Acknowledge receipt
res.status(200).send('OK');

// Process asynchronously
processWebhookEvent(event);
});

Step 3: Verify Webhook Signatures

Unizo signs all webhook payloads using HMAC-SHA256:

function verifyWebhook(payload, signature, timestamp) {
const webhookSecret = process.env.UNIZO_WEBHOOK_SECRET;

// Prevent replay attacks
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - parseInt(timestamp)) > 300) { // 5 minutes
return false;
}

// Verify signature
const expectedSignature = crypto
.createHmac('sha256', webhookSecret)
.update(`${timestamp}.${JSON.stringify(payload)}`)
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}

Step 4: Handle Different Event Types

Process events based on their type and source integration:

async function processWebhookEvent(event) {
const { type, integration, data } = event;

// Handle events by category
if (type.startsWith('scm.')) {
await handleSourceCodeEvent(type, integration, data);
} else if (type.startsWith('ticketing.')) {
await handleTicketingEvent(type, integration, data);
} else if (type.startsWith('identity.')) {
await handleIdentityEvent(type, integration, data);
}
}

// Example: Handle pull request events from any SCM platform
async function handleSourceCodeEvent(type, integration, data) {
if (type === 'scm.pull_request.created') {
// Same code works for GitHub, GitLab, Bitbucket, etc.
console.log(`New PR in ${integration.name}: ${data.title}`);

// Automatically create a linked ticket
await unizo.ticketing.createTicket({
integrationId: 'jira-prod',
title: `Review PR: ${data.title}`,
description: `PR #${data.number} needs review\n${data.url}`,
customFields: {
pr_url: data.url,
repository: data.repository.name
}
});
}
}

Event Structure

All webhook events follow a consistent structure:

{
"id": "evt_1234567890",
"type": "scm.pull_request.created",
"timestamp": "2024-01-15T10:30:00Z",
"integration": {
"id": "int_github_123",
"type": "github"
},
"data": {
// Event-specific data
}
}

Available Events by Category

Source Code Management

  • scm.repository.created
  • scm.pull_request.created
  • scm.pull_request.updated
  • scm.pull_request.merged
  • scm.commit.pushed
  • scm.branch.created
  • scm.branch.deleted

Ticketing

  • ticketing.ticket.created
  • ticketing.ticket.updated
  • ticketing.ticket.resolved
  • ticketing.comment.added

Identity

  • identity.user.created
  • identity.user.updated
  • identity.user.deactivated
  • identity.group.created
  • identity.group.membership.changed

Incident Management

  • incidents.incident.created
  • incidents.incident.acknowledged
  • incidents.incident.resolved
  • incidents.severity.changed

Best Practices

Idempotency

Store event IDs to handle duplicate deliveries:

const processedEvents = new Set();

function handleWebhook(event) {
if (processedEvents.has(event.id)) {
return; // Already processed
}

// Process event
processedEvents.add(event.id);
}

Async Processing

Return 200 OK immediately and process events asynchronously:

app.post('/webhooks', async (req, res) => {
// Acknowledge receipt immediately
res.status(200).send('OK');

// Process asynchronously
await queue.push({
type: 'webhook',
payload: req.body
});
});

Error Handling

Implement proper error handling and logging:

try {
await processWebhookEvent(event);
} catch (error) {
logger.error('Webhook processing failed', {
eventId: event.id,
error: error.message
});

// Return 500 to trigger retry
res.status(500).send('Processing failed');
}

Webhook Security

IP Whitelisting

Restrict webhook delivery to Unizo's IP addresses:

  • 52.10.128.0/24
  • 54.187.92.0/24

Request Validation

Always validate:

  1. Signature header matches payload
  2. Timestamp is within acceptable range (±5 minutes)
  3. Event ID hasn't been processed before

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

  • 1st retry: 1 minute
  • 2nd retry: 5 minutes
  • 3rd retry: 30 minutes
  • 4th retry: 2 hours
  • 5th retry: 12 hours

After 5 failed attempts, the webhook is marked as failed and can be manually replayed from the console.

Testing Webhooks

Use the Unizo Console to:

  • Send test events to your endpoint
  • View delivery attempts and responses
  • Replay failed webhooks
  • Monitor webhook metrics

Next Steps