Communication and Notification Integrations for AI Applications

This comprehensive guide covers modern patterns and best practices for integrating AI applications with communication platforms, notification systems, and conversational workflows in 2025.

🎯 Overview

Communication integrations enable AI systems to:

  • Send real-time notifications and alerts
  • Participate in conversational workflows
  • Automate support and incident response
  • Facilitate human-AI collaboration
  • Enable multi-channel presence

📱 Platform-Specific Integrations

Slack Integration

Webhook-Based Notifications

// Slack Incoming Webhook Implementation
class SlackNotifier {
  private webhookUrl: string;
  
  constructor(webhookUrl: string) {
    this.webhookUrl = webhookUrl;
  }
  
  async sendMessage(message: SlackMessage): Promise<void> {
    const response = await fetch(this.webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(message)
    });
    
    if (!response.ok) {
      throw new Error(`Slack webhook failed: ${response.statusText}`);
    }
  }
  
  // Rich message formatting
  async sendRichNotification(
    title: string,
    content: string,
    severity: 'info' | 'warning' | 'error',
    context?: Record<string, any>
  ) {
    const color = {
      info: '#36a64f',
      warning: '#ff9900',
      error: '#ff0000'
    }[severity];
    
    await this.sendMessage({
      attachments: [{
        color,
        title,
        text: content,
        fields: Object.entries(context || {}).map(([k, v]) => ({
          title: k,
          value: String(v),
          short: true
        })),
        ts: Math.floor(Date.now() / 1000)
      }]
    });
  }
}

Slack App with Claude Integration

import { App } from '@slack/bolt';
import { Anthropic } from '@anthropic-ai/sdk';
 
class ClaudeSlackBot {
  private app: App;
  private anthropic: Anthropic;
  private conversationHistory: Map<string, Message[]> = new Map();
  
  constructor() {
    this.app = new App({
      token: process.env.SLACK_BOT_TOKEN,
      signingSecret: process.env.SLACK_SIGNING_SECRET,
      socketMode: true,
      appToken: process.env.SLACK_APP_TOKEN
    });
    
    this.anthropic = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY
    });
    
    this.setupEventHandlers();
  }
  
  private setupEventHandlers() {
    // Handle direct messages
    this.app.message(async ({ message, say }) => {
      if (message.subtype) return; // Ignore bot messages
      
      const response = await this.generateResponse(
        message.text,
        message.channel
      );
      
      await say({
        text: response,
        thread_ts: message.thread_ts || message.ts
      });
    });
    
    // Handle mentions
    this.app.event('app_mention', async ({ event, say }) => {
      const response = await this.generateResponse(
        event.text,
        event.channel
      );
      
      await say({
        text: response,
        thread_ts: event.thread_ts || event.ts
      });
    });
    
    // Slash commands
    this.app.command('/claude', async ({ command, ack, respond }) => {
      await ack();
      
      const response = await this.generateResponse(
        command.text,
        command.channel_id
      );
      
      await respond({
        response_type: 'in_channel',
        text: response
      });
    });
  }
  
  private async generateResponse(
    prompt: string,
    channelId: string
  ): Promise<string> {
    // Get conversation history
    const history = this.conversationHistory.get(channelId) || [];
    
    try {
      const message = await this.anthropic.messages.create({
        model: 'claude-opus-4-20250514',
        messages: [
          ...history,
          { role: 'user', content: prompt }
        ],
        max_tokens: 1024
      });
      
      // Update history
      history.push(
        { role: 'user', content: prompt },
        { role: 'assistant', content: message.content[0].text }
      );
      this.conversationHistory.set(channelId, history.slice(-10)); // Keep last 10
      
      return message.content[0].text;
    } catch (error) {
      console.error('Claude API error:', error);
      return 'Sorry, I encountered an error processing your request.';
    }
  }
  
  async start() {
    await this.app.start();
    console.log('Claude Slack Bot is running!');
  }
}

Discord Integration

Discord Bot with AI Capabilities

import { Client, GatewayIntentBits, Message } from 'discord.js';
import { Anthropic } from '@anthropic-ai/sdk';
 
class ClaudeDiscordBot {
  private client: Client;
  private anthropic: Anthropic;
  private commandPrefix = '!claude';
  
  constructor() {
    this.client = new Client({
      intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent,
        GatewayIntentBits.DirectMessages
      ]
    });
    
    this.anthropic = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY
    });
    
    this.setupEventHandlers();
  }
  
  private setupEventHandlers() {
    this.client.on('ready', () => {
      console.log(`Logged in as ${this.client.user?.tag}!`);
    });
    
    this.client.on('messageCreate', async (message: Message) => {
      // Ignore bot messages
      if (message.author.bot) return;
      
      // Check for command or mention
      if (!message.content.startsWith(this.commandPrefix) && 
          !message.mentions.has(this.client.user!)) {
        return;
      }
      
      // Show typing indicator
      await message.channel.sendTyping();
      
      try {
        const prompt = message.content
          .replace(this.commandPrefix, '')
          .replace(`<@${this.client.user?.id}>`, '')
          .trim();
          
        const response = await this.generateResponse(prompt);
        
        // Split long responses
        const chunks = this.splitMessage(response);
        for (const chunk of chunks) {
          await message.reply(chunk);
        }
      } catch (error) {
        await message.reply('Sorry, I encountered an error!');
        console.error(error);
      }
    });
  }
  
  private async generateResponse(prompt: string): Promise<string> {
    const message = await this.anthropic.messages.create({
      model: 'claude-opus-4-20250514',
      messages: [{ role: 'user', content: prompt }],
      max_tokens: 1024
    });
    
    return message.content[0].text;
  }
  
  private splitMessage(text: string, maxLength = 2000): string[] {
    const chunks: string[] = [];
    let current = '';
    
    const lines = text.split('\n');
    for (const line of lines) {
      if (current.length + line.length + 1 > maxLength) {
        chunks.push(current);
        current = line;
      } else {
        current += (current ? '\n' : '') + line;
      }
    }
    
    if (current) chunks.push(current);
    return chunks;
  }
  
  async start() {
    await this.client.login(process.env.DISCORD_BOT_TOKEN);
  }
}

Discord Webhook Notifications

// Discord webhook for notifications
class DiscordWebhook {
  private webhookUrl: string;
  
  constructor(webhookUrl: string) {
    this.webhookUrl = webhookUrl;
  }
  
  async sendEmbed(embed: DiscordEmbed): Promise<void> {
    const response = await fetch(this.webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ embeds: [embed] })
    });
    
    if (!response.ok) {
      throw new Error(`Discord webhook failed: ${response.statusText}`);
    }
  }
  
  async sendAINotification(
    title: string,
    description: string,
    fields: Array<{ name: string; value: string }>,
    severity: 'success' | 'warning' | 'error'
  ) {
    const colors = {
      success: 0x00ff00,
      warning: 0xffaa00,
      error: 0xff0000
    };
    
    await this.sendEmbed({
      title,
      description,
      color: colors[severity],
      fields,
      timestamp: new Date().toISOString(),
      footer: {
        text: 'AI Notification System'
      }
    });
  }
}

Microsoft Teams Integration

Teams Adaptive Cards

class TeamsNotifier {
  private webhookUrl: string;
  
  constructor(webhookUrl: string) {
    this.webhookUrl = webhookUrl;
  }
  
  async sendAdaptiveCard(card: any): Promise<void> {
    const response = await fetch(this.webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        type: 'message',
        attachments: [{
          contentType: 'application/vnd.microsoft.card.adaptive',
          content: card
        }]
      })
    });
    
    if (!response.ok) {
      throw new Error(`Teams webhook failed: ${response.statusText}`);
    }
  }
  
  async sendAIAlert(
    title: string,
    message: string,
    data: Record<string, any>,
    actions?: Array<{ title: string; url: string }>
  ) {
    const card = {
      $schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
      type: 'AdaptiveCard',
      version: '1.4',
      body: [
        {
          type: 'TextBlock',
          text: title,
          size: 'Large',
          weight: 'Bolder'
        },
        {
          type: 'TextBlock',
          text: message,
          wrap: true
        },
        {
          type: 'FactSet',
          facts: Object.entries(data).map(([key, value]) => ({
            title: key,
            value: String(value)
          }))
        }
      ],
      actions: actions?.map(action => ({
        type: 'Action.OpenUrl',
        title: action.title,
        url: action.url
      }))
    };
    
    await this.sendAdaptiveCard(card);
  }
}

Email Integration (SendGrid)

AI-Powered Email Notifications

import sgMail from '@sendgrid/mail';
 
class AIEmailNotifier {
  constructor() {
    sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
  }
  
  async sendAIGeneratedEmail(
    to: string,
    subject: string,
    context: any,
    templateId?: string
  ) {
    const anthropic = new Anthropic();
    
    // Generate email content with AI
    const message = await anthropic.messages.create({
      model: 'claude-opus-4-20250514',
      messages: [{
        role: 'user',
        content: `Generate a professional email with the following context:
          Subject: ${subject}
          Context: ${JSON.stringify(context)}
          
          The email should be clear, concise, and actionable.`
      }],
      max_tokens: 500
    });
    
    const emailContent = message.content[0].text;
    
    const msg = {
      to,
      from: process.env.SENDER_EMAIL!,
      subject,
      text: emailContent,
      html: `<div style="font-family: Arial, sans-serif;">
        ${emailContent.replace(/\n/g, '<br>')}
      </div>`,
      ...(templateId && {
        templateId,
        dynamicTemplateData: {
          content: emailContent,
          ...context
        }
      })
    };
    
    await sgMail.send(msg);
  }
  
  async sendBatchNotifications(
    recipients: Array<{ email: string; data: any }>,
    templateId: string
  ) {
    const messages = recipients.map(recipient => ({
      to: recipient.email,
      from: process.env.SENDER_EMAIL!,
      templateId,
      dynamicTemplateData: recipient.data
    }));
    
    // SendGrid supports up to 1000 recipients per request
    const chunks = this.chunkArray(messages, 1000);
    
    for (const chunk of chunks) {
      await sgMail.send(chunk);
    }
  }
  
  private chunkArray<T>(arr: T[], size: number): T[][] {
    const chunks: T[][] = [];
    for (let i = 0; i < arr.length; i += size) {
      chunks.push(arr.slice(i, i + size));
    }
    return chunks;
  }
}

🔔 Webhook Patterns

Secure Webhook Handler

import crypto from 'crypto';
 
class SecureWebhookHandler {
  private secret: string;
  private handlers: Map<string, WebhookHandler> = new Map();
  
  constructor(secret: string) {
    this.secret = secret;
  }
  
  // Verify webhook signature
  verifySignature(
    payload: string,
    signature: string,
    timestamp: string
  ): boolean {
    const signedContent = `${timestamp}.${payload}`;
    const expectedSignature = crypto
      .createHmac('sha256', this.secret)
      .update(signedContent)
      .digest('hex');
    
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  }
  
  // Register webhook handler
  on(event: string, handler: WebhookHandler) {
    this.handlers.set(event, handler);
  }
  
  // Process incoming webhook
  async processWebhook(
    event: string,
    payload: any,
    headers: Record<string, string>
  ): Promise<any> {
    // Verify timestamp to prevent replay attacks
    const timestamp = headers['x-webhook-timestamp'];
    const timeDiff = Date.now() - parseInt(timestamp) * 1000;
    
    if (timeDiff > 300000) { // 5 minutes
      throw new Error('Webhook timestamp too old');
    }
    
    // Verify signature
    const signature = headers['x-webhook-signature'];
    if (!this.verifySignature(JSON.stringify(payload), signature, timestamp)) {
      throw new Error('Invalid webhook signature');
    }
    
    // Execute handler
    const handler = this.handlers.get(event);
    if (!handler) {
      throw new Error(`No handler for event: ${event}`);
    }
    
    return await handler(payload);
  }
}
 
// Express middleware for webhooks
export function webhookMiddleware(handler: SecureWebhookHandler) {
  return async (req: Request, res: Response, next: NextFunction) => {
    try {
      const result = await handler.processWebhook(
        req.params.event,
        req.body,
        req.headers as Record<string, string>
      );
      
      res.json({ success: true, result });
    } catch (error) {
      res.status(400).json({ 
        success: false, 
        error: error.message 
      });
    }
  };
}

Webhook Retry Logic

class WebhookClient {
  private maxRetries = 3;
  private retryDelay = 1000; // Start with 1 second
  
  async sendWithRetry(
    url: string,
    payload: any,
    options?: RequestInit
  ): Promise<Response> {
    let lastError: Error | null = null;
    
    for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
      try {
        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            ...options?.headers
          },
          body: JSON.stringify(payload),
          ...options
        });
        
        // Retry on 5xx errors
        if (response.status >= 500 && attempt < this.maxRetries) {
          throw new Error(`Server error: ${response.status}`);
        }
        
        return response;
      } catch (error) {
        lastError = error as Error;
        
        if (attempt < this.maxRetries) {
          // Exponential backoff with jitter
          const delay = this.retryDelay * Math.pow(2, attempt) + 
                       Math.random() * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    
    throw lastError || new Error('Webhook send failed');
  }
}

🚨 Alert Routing and Escalation

Intelligent Alert Router

interface AlertRule {
  id: string;
  condition: (alert: Alert) => boolean;
  channels: string[];
  escalation?: EscalationPolicy;
}
 
class AlertRouter {
  private rules: AlertRule[] = [];
  private channels: Map<string, NotificationChannel> = new Map();
  
  // Register notification channels
  registerChannel(name: string, channel: NotificationChannel) {
    this.channels.set(name, channel);
  }
  
  // Add routing rule
  addRule(rule: AlertRule) {
    this.rules.push(rule);
  }
  
  // Route alert based on rules
  async routeAlert(alert: Alert): Promise<void> {
    const matchingRules = this.rules.filter(rule => 
      rule.condition(alert)
    );
    
    if (matchingRules.length === 0) {
      // Default routing
      await this.sendToChannel('default', alert);
      return;
    }
    
    // Send to all matching channels
    const promises = matchingRules.flatMap(rule =>
      rule.channels.map(channelName => 
        this.sendToChannel(channelName, alert)
      )
    );
    
    await Promise.all(promises);
    
    // Handle escalation if needed
    for (const rule of matchingRules) {
      if (rule.escalation) {
        await this.scheduleEscalation(alert, rule.escalation);
      }
    }
  }
  
  private async sendToChannel(
    channelName: string,
    alert: Alert
  ): Promise<void> {
    const channel = this.channels.get(channelName);
    if (!channel) {
      console.error(`Unknown channel: ${channelName}`);
      return;
    }
    
    try {
      await channel.send(alert);
    } catch (error) {
      console.error(`Failed to send to ${channelName}:`, error);
      // Could implement fallback channel here
    }
  }
  
  private async scheduleEscalation(
    alert: Alert,
    policy: EscalationPolicy
  ): Promise<void> {
    setTimeout(async () => {
      // Check if alert is still active
      if (await this.isAlertActive(alert.id)) {
        await this.escalate(alert, policy);
      }
    }, policy.delayMs);
  }
}
 
// Example usage
const router = new AlertRouter();
 
// Register channels
router.registerChannel('slack', new SlackChannel());
router.registerChannel('email', new EmailChannel());
router.registerChannel('pagerduty', new PagerDutyChannel());
 
// Add routing rules
router.addRule({
  id: 'critical-errors',
  condition: (alert) => alert.severity === 'critical',
  channels: ['slack', 'pagerduty'],
  escalation: {
    delayMs: 5 * 60 * 1000, // 5 minutes
    channels: ['email', 'phone']
  }
});
 
router.addRule({
  id: 'ai-model-errors',
  condition: (alert) => alert.tags.includes('ai-model'),
  channels: ['slack', 'email']
});

🤖 Conversational AI Patterns

Multi-Turn Conversation Manager

interface ConversationState {
  id: string;
  userId: string;
  context: Message[];
  metadata: Record<string, any>;
  lastActivity: Date;
}
 
class ConversationManager {
  private conversations: Map<string, ConversationState> = new Map();
  private maxContextLength = 20;
  private sessionTimeout = 30 * 60 * 1000; // 30 minutes
  
  async processMessage(
    userId: string,
    message: string,
    channel: 'slack' | 'discord' | 'teams'
  ): Promise<string> {
    const conversation = this.getOrCreateConversation(userId);
    
    // Add user message to context
    conversation.context.push({
      role: 'user',
      content: message,
      timestamp: new Date()
    });
    
    // Generate AI response
    const response = await this.generateResponse(
      conversation,
      channel
    );
    
    // Add assistant response to context
    conversation.context.push({
      role: 'assistant',
      content: response,
      timestamp: new Date()
    });
    
    // Trim context if too long
    if (conversation.context.length > this.maxContextLength) {
      conversation.context = conversation.context.slice(-this.maxContextLength);
    }
    
    conversation.lastActivity = new Date();
    
    return response;
  }
  
  private async generateResponse(
    conversation: ConversationState,
    channel: string
  ): Promise<string> {
    const anthropic = new Anthropic();
    
    // Add channel-specific context
    const systemPrompt = this.getSystemPrompt(channel);
    
    const message = await anthropic.messages.create({
      model: 'claude-opus-4-20250514',
      system: systemPrompt,
      messages: conversation.context.map(msg => ({
        role: msg.role,
        content: msg.content
      })),
      max_tokens: 1024
    });
    
    return message.content[0].text;
  }
  
  private getSystemPrompt(channel: string): string {
    const prompts = {
      slack: 'You are a helpful AI assistant in Slack. Use emoji and formatting appropriate for Slack.',
      discord: 'You are a helpful AI assistant in Discord. Be friendly and use Discord-appropriate formatting.',
      teams: 'You are a professional AI assistant in Microsoft Teams. Maintain a professional tone.'
    };
    
    return prompts[channel] || 'You are a helpful AI assistant.';
  }
  
  // Clean up inactive conversations
  startCleanupInterval() {
    setInterval(() => {
      const now = Date.now();
      
      for (const [id, conversation] of this.conversations) {
        if (now - conversation.lastActivity.getTime() > this.sessionTimeout) {
          this.conversations.delete(id);
        }
      }
    }, 60000); // Check every minute
  }
}

Intent Recognition and Routing

interface Intent {
  name: string;
  confidence: number;
  parameters: Record<string, any>;
}
 
class IntentRouter {
  private handlers: Map<string, IntentHandler> = new Map();
  
  // Register intent handlers
  on(intent: string, handler: IntentHandler) {
    this.handlers.set(intent, handler);
  }
  
  async processMessage(message: string): Promise<any> {
    // Extract intent using AI
    const intent = await this.extractIntent(message);
    
    if (intent.confidence < 0.7) {
      return this.handleUncertainIntent(message, intent);
    }
    
    const handler = this.handlers.get(intent.name);
    if (!handler) {
      return this.handleUnknownIntent(intent);
    }
    
    return await handler(intent.parameters, message);
  }
  
  private async extractIntent(message: string): Promise<Intent> {
    const anthropic = new Anthropic();
    
    const response = await anthropic.messages.create({
      model: 'claude-opus-4-20250514',
      messages: [{
        role: 'user',
        content: `Extract the intent and parameters from this message:
          "${message}"
          
          Respond in JSON format:
          {
            "name": "intent_name",
            "confidence": 0.0-1.0,
            "parameters": {}
          }`
      }],
      max_tokens: 200
    });
    
    return JSON.parse(response.content[0].text);
  }
}
 
// Example usage
const router = new IntentRouter();
 
router.on('create_ticket', async (params) => {
  // Create support ticket
  return `Created ticket: ${params.title}`;
});
 
router.on('check_status', async (params) => {
  // Check status
  return `Status of ${params.item}: Active`;
});

🔐 Security Best Practices

JWT Authentication for Webhooks

import jwt from 'jsonwebtoken';
 
class JWTWebhookAuth {
  private secret: string;
  private issuer: string;
  
  constructor(secret: string, issuer: string) {
    this.secret = secret;
    this.issuer = issuer;
  }
  
  // Generate webhook token
  generateToken(
    webhookId: string,
    expiresIn: string = '5m'
  ): string {
    return jwt.sign(
      {
        webhookId,
        iss: this.issuer,
        iat: Math.floor(Date.now() / 1000)
      },
      this.secret,
      { expiresIn }
    );
  }
  
  // Verify incoming webhook
  verifyToken(token: string): any {
    try {
      const decoded = jwt.verify(token, this.secret, {
        issuer: this.issuer,
        clockTolerance: 30 // 30 seconds
      });
      
      return decoded;
    } catch (error) {
      if (error.name === 'TokenExpiredError') {
        throw new Error('Webhook token expired');
      }
      throw new Error('Invalid webhook token');
    }
  }
  
  // Express middleware
  middleware() {
    return (req: Request, res: Response, next: NextFunction) => {
      const token = req.headers.authorization?.replace('Bearer ', '');
      
      if (!token) {
        return res.status(401).json({ error: 'No token provided' });
      }
      
      try {
        const decoded = this.verifyToken(token);
        req.webhookAuth = decoded;
        next();
      } catch (error) {
        res.status(401).json({ error: error.message });
      }
    };
  }
}

Rate Limiting for AI Endpoints

class AIRateLimiter {
  private limits: Map<string, RateLimit> = new Map();
  
  constructor(
    private windowMs: number = 60000, // 1 minute
    private maxRequests: number = 10
  ) {}
  
  async checkLimit(userId: string): Promise<boolean> {
    const now = Date.now();
    let userLimit = this.limits.get(userId);
    
    if (!userLimit || now > userLimit.resetTime) {
      userLimit = {
        count: 0,
        resetTime: now + this.windowMs
      };
      this.limits.set(userId, userLimit);
    }
    
    if (userLimit.count >= this.maxRequests) {
      return false;
    }
    
    userLimit.count++;
    return true;
  }
  
  // Get remaining requests
  getRemaining(userId: string): number {
    const userLimit = this.limits.get(userId);
    if (!userLimit) return this.maxRequests;
    
    return Math.max(0, this.maxRequests - userLimit.count);
  }
  
  // Express middleware
  middleware() {
    return async (req: Request, res: Response, next: NextFunction) => {
      const userId = req.user?.id || req.ip;
      
      if (!await this.checkLimit(userId)) {
        const resetTime = this.limits.get(userId)?.resetTime || 0;
        
        return res.status(429).json({
          error: 'Rate limit exceeded',
          retryAfter: Math.ceil((resetTime - Date.now()) / 1000)
        });
      }
      
      res.setHeader('X-RateLimit-Remaining', this.getRemaining(userId));
      next();
    };
  }
}

📊 Monitoring and Analytics

Communication Analytics

class CommunicationAnalytics {
  private metrics: Map<string, Metric> = new Map();
  
  // Track message
  trackMessage(
    channel: string,
    type: 'sent' | 'received' | 'failed',
    metadata?: Record<string, any>
  ) {
    const key = `${channel}:${type}`;
    const metric = this.metrics.get(key) || {
      count: 0,
      lastUpdated: new Date()
    };
    
    metric.count++;
    metric.lastUpdated = new Date();
    
    if (metadata) {
      metric.metadata = { ...metric.metadata, ...metadata };
    }
    
    this.metrics.set(key, metric);
  }
  
  // Get channel statistics
  getChannelStats(channel: string): ChannelStats {
    const sent = this.metrics.get(`${channel}:sent`)?.count || 0;
    const received = this.metrics.get(`${channel}:received`)?.count || 0;
    const failed = this.metrics.get(`${channel}:failed`)?.count || 0;
    
    return {
      channel,
      sent,
      received,
      failed,
      successRate: sent > 0 ? (sent - failed) / sent : 0,
      totalMessages: sent + received
    };
  }
  
  // Export metrics for monitoring
  exportMetrics(): Record<string, any> {
    const metrics: Record<string, any> = {};
    
    for (const [key, value] of this.metrics) {
      metrics[key] = value.count;
    }
    
    return metrics;
  }
}

🎯 Best Practices Summary

1. Architecture

  • Use event-driven patterns for real-time communication
  • Implement proper retry logic with exponential backoff
  • Design for horizontal scalability
  • Use message queues for reliable delivery

2. Security

  • Always authenticate webhooks (HMAC, JWT)
  • Implement rate limiting
  • Validate and sanitize all inputs
  • Use encryption for sensitive data
  • Rotate secrets regularly

3. User Experience

  • Provide clear error messages
  • Implement typing indicators
  • Support rich media formats
  • Enable smooth human handoff
  • Respect platform-specific conventions

4. Monitoring

  • Track delivery rates and latencies
  • Monitor error rates by channel
  • Set up alerts for anomalies
  • Log all interactions for debugging
  • Implement health checks

5. Compliance

  • Respect user privacy settings
  • Implement data retention policies
  • Allow users to opt-out
  • Maintain audit logs
  • Follow platform ToS

📚 External References


Last Updated: 2025-07-23 Research compiled from industry best practices and real-world implementations