Webhook-uri Custom
Integrează VAI Portal cu orice sistem prin webhooks custom pentru transfer de date în timp real și sincronizare cu platformele tale preferate.
Universal Integration
Conectează VAI cu orice sistem care suportă HTTP endpoints.
Real-time Events
Trimite evenimente instantaneu către sisteme externe.
Data Transformation
Transformă și formatează datele pentru compatibilitate.
Secure Delivery
Autentificare și criptare pentru transferuri sigure.
Arhitectura Integrării
VAI Portal
Event Generator
Webhook Engine
Event Dispatcher
Custom Systems
HTTP Endpoints
Evenimente Disponibile
conversation.started
Când începe o nouă conversație cu un agent AI
message.received
Când agentul primește un mesaj de la utilizator
message.sent
Când agentul trimite un răspuns
conversation.ended
Când se încheie o conversație
Cazuri de Utilizare
CRM Integration
Sincronizează lead-uri și conversații cu CRM-uri custom.
VAI Agent → Lead Capture → Webhook → Custom CRM
↓ ↓ ↓
Data Format HTTP POST Database Update
Analytics Pipeline
Trimite date de analiză către sisteme de business intelligence.
VAI Agent → Event Data → Webhook → Analytics Platform
↓ ↓ ↓
Metrics Pack JSON Payload Data Processing
Notification Systems
Integrează cu sisteme de notificare custom (Slack, Teams, Email).
VAI Agent → Trigger Event → Webhook → Notification Service
↓ ↓ ↓
Event Type HTTP Request Message Delivery
Exemple de Implementare
Custom Webhook Integration
// Custom Webhook Integration for VAI Portal
const crypto = require('crypto');
const axios = require('axios');
class CustomWebhookIntegration {
constructor() {
this.webhooks = new Map(); // Store webhook configurations
this.retryAttempts = 3;
this.timeout = 10000; // 10 seconds
}
async registerWebhook(webhookConfig) {
const {
id,
url,
events,
secret,
headers = {},
retryConfig = {},
dataTransform = null
} = webhookConfig;
try {
// Validate webhook URL
await this.validateWebhookUrl(url);
// Store webhook configuration
this.webhooks.set(id, {
url,
events: new Set(events),
secret,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'VAI-Portal-Webhook/1.0',
...headers
},
retryConfig: {
maxAttempts: retryConfig.maxAttempts || this.retryAttempts,
backoffMs: retryConfig.backoffMs || 1000,
...retryConfig
},
dataTransform,
status: 'active',
stats: {
sent: 0,
failed: 0,
lastSent: null
}
});
console.log(`Webhook registered: ${id} for events: ${events.join(', ')}`);
return {
success: true,
webhookId: id,
message: 'Webhook registered successfully'
};
} catch (error) {
console.error('Error registering webhook:', error);
return {
success: false,
error: error.message
};
}
}
async validateWebhookUrl(url) {
try {
// Test connectivity to webhook URL
const response = await axios.get(url, {
timeout: 5000,
validateStatus: (status) => status < 500
});
if (response.status >= 400) {
throw new Error(`Webhook URL returned status ${response.status}`);
}
return true;
} catch (error) {
if (error.code === 'ECONNREFUSED') {
throw new Error('Webhook URL is not accessible');
}
throw error;
}
}
async triggerWebhook(eventType, eventData) {
const promises = [];
// Find all webhooks that should receive this event
for (const [webhookId, webhook] of this.webhooks) {
if (webhook.events.has(eventType) && webhook.status === 'active') {
promises.push(
this.sendWebhook(webhookId, webhook, eventType, eventData)
.catch(error => {
console.error(`Webhook ${webhookId} failed:`, error);
return { webhookId, success: false, error: error.message };
})
);
}
}
// Wait for all webhooks to complete
const results = await Promise.allSettled(promises);
return results.map(result =>
result.status === 'fulfilled' ? result.value : { success: false, error: result.reason }
);
}
async sendWebhook(webhookId, webhook, eventType, eventData) {
const startTime = Date.now();
try {
// Prepare webhook payload
const payload = this.preparePayload(eventType, eventData, webhook);
// Generate signature if secret is provided
const signature = webhook.secret
? this.generateSignature(payload, webhook.secret)
: null;
// Prepare headers
const headers = {
...webhook.headers,
'X-VAI-Event': eventType,
'X-VAI-Webhook-ID': webhookId,
'X-VAI-Timestamp': Date.now().toString()
};
if (signature) {
headers['X-VAI-Signature'] = signature;
}
// Send webhook with retry logic
const response = await this.sendWithRetry(webhook.url, payload, headers, webhook.retryConfig);
// Update webhook stats
webhook.stats.sent++;
webhook.stats.lastSent = new Date().toISOString();
console.log(`Webhook ${webhookId} delivered successfully in ${Date.now() - startTime}ms`);
return {
webhookId,
success: true,
statusCode: response.status,
duration: Date.now() - startTime
};
} catch (error) {
webhook.stats.failed++;
console.error(`Webhook ${webhookId} delivery failed:`, error);
return {
webhookId,
success: false,
error: error.message,
duration: Date.now() - startTime
};
}
}
preparePayload(eventType, eventData, webhook) {
let payload = {
event: eventType,
timestamp: new Date().toISOString(),
data: eventData
};
// Apply data transformation if configured
if (webhook.dataTransform && typeof webhook.dataTransform === 'function') {
try {
payload = webhook.dataTransform(payload);
} catch (error) {
console.error('Data transformation failed:', error);
// Continue with original payload
}
}
return payload;
}
generateSignature(payload, secret) {
const payloadString = JSON.stringify(payload);
return crypto
.createHmac('sha256', secret)
.update(payloadString)
.digest('hex');
}
async sendWithRetry(url, payload, headers, retryConfig) {
let lastError;
for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt++) {
try {
const response = await axios.post(url, payload, {
headers,
timeout: this.timeout,
validateStatus: (status) => status >= 200 && status < 300
});
return response;
} catch (error) {
lastError = error;
if (attempt < retryConfig.maxAttempts) {
const delay = retryConfig.backoffMs * Math.pow(2, attempt - 1);
console.log(`Webhook attempt ${attempt} failed, retrying in ${delay}ms...`);
await this.sleep(delay);
}
}
}
throw lastError;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = this.generateSignature(payload, secret);
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
getWebhookStats(webhookId) {
const webhook = this.webhooks.get(webhookId);
if (!webhook) {
return { error: 'Webhook not found' };
}
return {
webhookId,
status: webhook.status,
events: Array.from(webhook.events),
stats: webhook.stats,
url: webhook.url.replace(/\/\/[^@]+@/, '//***@') // Hide sensitive parts
};
}
getAllWebhookStats() {
const stats = {};
for (const [webhookId, webhook] of this.webhooks) {
stats[webhookId] = {
status: webhook.status,
events: Array.from(webhook.events),
stats: webhook.stats,
url: webhook.url.replace(/\/\/[^@]+@/, '//***@')
};
}
return stats;
}
async updateWebhook(webhookId, updates) {
const webhook = this.webhooks.get(webhookId);
if (!webhook) {
return { success: false, error: 'Webhook not found' };
}
try {
// Apply updates
Object.assign(webhook, updates);
// Validate URL if updated
if (updates.url) {
await this.validateWebhookUrl(updates.url);
}
return {
success: true,
message: 'Webhook updated successfully'
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
async deleteWebhook(webhookId) {
const webhook = this.webhooks.get(webhookId);
if (!webhook) {
return { success: false, error: 'Webhook not found' };
}
this.webhooks.delete(webhookId);
return {
success: true,
message: 'Webhook deleted successfully'
};
}
async testWebhook(webhookId, testEvent = 'webhook.test') {
const webhook = this.webhooks.get(webhookId);
if (!webhook) {
return { success: false, error: 'Webhook not found' };
}
const testData = {
test: true,
timestamp: new Date().toISOString(),
webhookId: webhookId,
message: 'This is a test webhook from VAI Portal'
};
try {
const results = await this.triggerWebhook(testEvent, testData);
const result = results.find(r => r.webhookId === webhookId);
return {
success: result.success,
message: result.success
? 'Test webhook delivered successfully'
: `Test webhook failed: ${result.error}`,
details: result
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
}
// VAI Event Handlers
class VAIEventHandler {
constructor(webhookIntegration) {
this.webhookIntegration = webhookIntegration;
}
async handleConversationStarted(conversationData) {
const {
sessionId,
agentId,
userId,
platform,
userAgent,
timestamp
} = conversationData;
const eventData = {
sessionId,
agentId,
userId,
platform,
userAgent,
timestamp: timestamp || new Date().toISOString()
};
return await this.webhookIntegration.triggerWebhook('conversation.started', eventData);
}
async handleMessageReceived(messageData) {
const {
sessionId,
message,
userId,
platform,
intent,
entities,
timestamp
} = messageData;
const eventData = {
sessionId,
message: {
text: message.text,
type: message.type || 'text',
metadata: message.metadata || {}
},
userId,
platform,
intent,
entities: entities || [],
timestamp: timestamp || new Date().toISOString()
};
return await this.webhookIntegration.triggerWebhook('message.received', eventData);
}
async handleMessageSent(responseData) {
const {
sessionId,
response,
agentId,
confidence,
processingTime,
timestamp
} = responseData;
const eventData = {
sessionId,
response: {
text: response.text,
type: response.type || 'text',
metadata: response.metadata || {}
},
agentId,
confidence,
processingTime,
timestamp: timestamp || new Date().toISOString()
};
return await this.webhookIntegration.triggerWebhook('message.sent', eventData);
}
async handleConversationEnded(conversationData) {
const {
sessionId,
duration,
messageCount,
summary,
satisfaction,
resolved,
timestamp
} = conversationData;
const eventData = {
sessionId,
duration,
messageCount,
summary,
satisfaction,
resolved,
timestamp: timestamp || new Date().toISOString()
};
return await this.webhookIntegration.triggerWebhook('conversation.ended', eventData);
}
async handleAgentMetrics(metricsData) {
const {
agentId,
metrics,
period,
timestamp
} = metricsData;
const eventData = {
agentId,
metrics: {
totalConversations: metrics.totalConversations,
averageResponseTime: metrics.averageResponseTime,
satisfactionScore: metrics.satisfactionScore,
resolutionRate: metrics.resolutionRate,
...metrics
},
period,
timestamp: timestamp || new Date().toISOString()
};
return await this.webhookIntegration.triggerWebhook('agent.metrics', eventData);
}
}
module.exports = {
CustomWebhookIntegration,
VAIEventHandler
};Webhook Receiver Example
// Webhook Receiver Example for Custom Integration
const express = require('express');
const crypto = require('crypto');
const app = express();
// Middleware to parse JSON bodies
app.use(express.json({
verify: (req, res, buf) => {
req.rawBody = buf;
}
}));
// Webhook secret (should be stored securely)
const WEBHOOK_SECRET = process.env.VAI_WEBHOOK_SECRET || 'your-webhook-secret';
// Verify webhook signature
function verifySignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Main webhook endpoint
app.post('/webhooks/vai', (req, res) => {
try {
const signature = req.headers['x-vai-signature'];
const eventType = req.headers['x-vai-event'];
const webhookId = req.headers['x-vai-webhook-id'];
const timestamp = req.headers['x-vai-timestamp'];
// Verify webhook signature
if (!verifySignature(req.rawBody, signature, WEBHOOK_SECRET)) {
console.error('Invalid webhook signature');
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook event
console.log(`Received webhook event: ${eventType} from ${webhookId}`);
// Route to appropriate handler
switch (eventType) {
case 'conversation.started':
handleConversationStarted(req.body);
break;
case 'message.received':
handleMessageReceived(req.body);
break;
case 'message.sent':
handleMessageSent(req.body);
break;
case 'conversation.ended':
handleConversationEnded(req.body);
break;
case 'agent.metrics':
handleAgentMetrics(req.body);
break;
case 'webhook.test':
handleWebhookTest(req.body);
break;
default:
console.log(`Unhandled event type: ${eventType}`);
}
// Acknowledge receipt
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Event handlers
function handleConversationStarted(data) {
const { event, timestamp, data: eventData } = data;
console.log('Conversation started:', {
sessionId: eventData.sessionId,
agentId: eventData.agentId,
userId: eventData.userId,
platform: eventData.platform,
timestamp
});
// Example: Store in database
storeConversationStart(eventData);
// Example: Send notification
sendNotification('New conversation started', {
sessionId: eventData.sessionId,
agent: eventData.agentId
});
}
function handleMessageReceived(data) {
const { event, timestamp, data: eventData } = data;
console.log('Message received:', {
sessionId: eventData.sessionId,
message: eventData.message.text,
userId: eventData.userId,
intent: eventData.intent
});
// Example: Log message for analytics
logMessageForAnalytics(eventData);
// Example: Update user activity
updateUserActivity(eventData.userId, 'message_received');
}
function handleMessageSent(data) {
const { event, timestamp, data: eventData } = data;
console.log('Message sent:', {
sessionId: eventData.sessionId,
response: eventData.response.text,
agentId: eventData.agentId,
confidence: eventData.confidence
});
// Example: Log response quality
logResponseQuality(eventData);
// Example: Update agent metrics
updateAgentMetrics(eventData.agentId, {
responseTime: eventData.processingTime,
confidence: eventData.confidence
});
}
function handleConversationEnded(data) {
const { event, timestamp, data: eventData } = data;
console.log('Conversation ended:', {
sessionId: eventData.sessionId,
duration: eventData.duration,
messageCount: eventData.messageCount,
resolved: eventData.resolved
});
// Example: Generate conversation summary
generateConversationSummary(eventData);
// Example: Update satisfaction metrics
updateSatisfactionMetrics(eventData);
// Example: Trigger follow-up actions
if (eventData.resolved) {
triggerFollowUpActions(eventData);
}
}
function handleAgentMetrics(data) {
const { event, timestamp, data: eventData } = data;
console.log('Agent metrics:', {
agentId: eventData.agentId,
period: eventData.period,
totalConversations: eventData.metrics.totalConversations,
satisfactionScore: eventData.metrics.satisfactionScore
});
// Example: Store performance metrics
storePerformanceMetrics(eventData);
// Example: Check for performance alerts
checkPerformanceAlerts(eventData);
}
function handleWebhookTest(data) {
console.log('Webhook test received:', data);
// Example: Update webhook status
updateWebhookStatus('active');
}
// Database operations (examples)
async function storeConversationStart(data) {
// Implementation depends on your database
console.log('Storing conversation start:', data.sessionId);
}
async function logMessageForAnalytics(data) {
// Implementation for analytics logging
console.log('Logging message for analytics:', data.sessionId);
}
async function logResponseQuality(data) {
// Implementation for response quality tracking
console.log('Logging response quality:', {
agentId: data.agentId,
confidence: data.confidence
});
}
async function generateConversationSummary(data) {
// Implementation for conversation summarization
console.log('Generating summary for conversation:', data.sessionId);
}
// Notification system (example)
function sendNotification(title, data) {
// Implementation for notifications (email, Slack, etc.)
console.log('Notification:', title, data);
}
// Metrics and analytics (examples)
function updateUserActivity(userId, activity) {
console.log('Updating user activity:', userId, activity);
}
function updateAgentMetrics(agentId, metrics) {
console.log('Updating agent metrics:', agentId, metrics);
}
function updateSatisfactionMetrics(data) {
console.log('Updating satisfaction metrics:', data.sessionId);
}
function storePerformanceMetrics(data) {
console.log('Storing performance metrics:', data.agentId);
}
function checkPerformanceAlerts(data) {
// Check if metrics fall below thresholds
if (data.metrics.satisfactionScore < 0.8) {
sendNotification('Low satisfaction alert', {
agentId: data.agentId,
score: data.metrics.satisfactionScore
});
}
}
function updateWebhookStatus(status) {
console.log('Webhook status updated:', status);
}
function triggerFollowUpActions(data) {
console.log('Triggering follow-up actions for conversation:', data.sessionId);
}
// Health check endpoint
app.get('/health', (req, res) => {
res.json({ status: 'healthy', timestamp: new Date().toISOString() });
});
// Webhook status endpoint
app.get('/webhook/status', (req, res) => {
res.json({
status: 'active',
lastReceived: new Date().toISOString(),
totalReceived: getWebhookStats()
});
});
function getWebhookStats() {
// Return webhook statistics
return {
conversationStarted: 0,
messageReceived: 0,
messageSent: 0,
conversationEnded: 0,
agentMetrics: 0
};
}
const PORT = process.env.PORT || 3004;
app.listen(PORT, () => {
console.log(`Webhook receiver listening on port ${PORT}`);
console.log(`Webhook endpoint: http://localhost:${PORT}/webhooks/vai`);
});Ghid de Configurare
Creează Endpoint HTTP
Dezvoltă un server care primește request-uri POST cu date JSON.
POST /webhooks/vai → JSON payload → 200 OKImplementează Verificare Signature
Verifică semnătura HMAC pentru a valida proveniența webhook-urilor.
Procesează Evenimente
Implementează logici pentru fiecare tip de eveniment primit.
Testează Integrarea
Folosește test webhooks pentru a verifica funcționalitatea.
Beneficii
Flexibilitate Maximă
Conectare cu orice sistem HTTP.
Timp Real
Transfer instantaneu de date și evenimente.
Securitate
Semnături criptate și validare.
Scalabilitate
Suport pentru volume mari de evenimente.
Pregătit pentru Webhooks Custom?
Integrează VAI Portal cu sistemele tale prin webhooks custom pentru a sincroniza date și a automatiza fluxurile de lucru.