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
🔗 Related Resources
- WebSocket Patterns for AI
- n8n Workflow Automation
- Security Deep Dive
- Real-Time Collaboration
- MCP Automation Patterns
📚 External References
- Slack API Documentation
- Discord Developer Portal
- Microsoft Teams Bot Framework
- SendGrid Email API
- Webhook.site for Testing
- ngrok for Local Development
Last Updated: 2025-07-23 Research compiled from industry best practices and real-world implementations