Inapoi la Integrari
🔗

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

HTTP POST & Signatures

Evenimente Disponibile

conversation.started

Per conversation

Când începe o nouă conversație cu un agent AI

sessionId
agentId
userId
timestamp
platform

message.received

Per message

Când agentul primește un mesaj de la utilizator

sessionId
message
userId
timestamp
intent

message.sent

Per response

Când agentul trimite un răspuns

sessionId
response
agentId
timestamp
confidence

conversation.ended

Per conversation

Când se încheie o conversație

sessionId
duration
messageCount
summary
timestamp

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

1

Creează Endpoint HTTP

Dezvoltă un server care primește request-uri POST cu date JSON.

POST /webhooks/vai → JSON payload → 200 OK
2

Implementează Verificare Signature

Verifică semnătura HMAC pentru a valida proveniența webhook-urilor.

3

Procesează Evenimente

Implementează logici pentru fiecare tip de eveniment primit.

4

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.