const express = require('express');
const app = express();
app.use(express.json());
// Start webhook handler - accept/reject calls
async function handleStartWebhook(payload, res) {
const { callId, callAdditionalData, originalAgentConfig } = payload;
try {
// Example: Check if customer is allowed to call
const customerId = callAdditionalData?.customerId;
const isAllowed = await checkCustomerStatus(customerId);
if (!isAllowed) {
return res.json({
accept: false,
reasonMessage: 'Customer account is not active'
});
}
// Example: Override config based on customer tier
const customerTier = await getCustomerTier(customerId);
if (customerTier === 'premium') {
return res.json({
accept: true,
overrideAgentConfig: {
...originalAgentConfig,
llmConfig: {
...originalAgentConfig.llmConfig,
model: 'gpt-4.1' // Upgrade to better model for premium
}
},
additionalData: {
customerTier: 'premium'
}
});
}
// Accept with default config
return res.json({ accept: true });
} catch (error) {
console.error('Start webhook error:', error);
// On error, accept with default config
return res.json({ accept: true });
}
}
// Completed webhook handler - process results
async function handleCompletedWebhook(payload) {
const {
callId,
transcription,
result,
durationSeconds,
callAdditionalData
} = payload;
// Store call data
await storeCallRecord({
callId,
customerId: callAdditionalData?.customerId,
duration: durationSeconds,
transcript: transcription,
postCallAnalysis: result.postCallAnalysis,
finishReason: result.finishReason
});
// Trigger follow-up actions based on analysis
if (result.postCallAnalysis?.issueResolved === false) {
await createFollowUpTask(callId, callAdditionalData?.customerId);
}
}
// Failed webhook handler - handle errors
async function handleFailedWebhook(payload) {
const { callId, errorMessage, callAdditionalData } = payload;
await logCallFailure({
callId,
customerId: callAdditionalData?.customerId,
error: errorMessage
});
// Alert on repeated failures
const recentFailures = await getRecentFailureCount(
callAdditionalData?.customerId,
'1h'
);
if (recentFailures > 3) {
await alertOperations('High failure rate for customer');
}
}
// Transfer webhook handler - route calls
async function handleTransferWebhook(payload, res) {
const { callAdditionalData, transferReason } = payload;
try {
// Route based on customer tier or transfer reason
const customerId = callAdditionalData?.customerId;
const accountTier = callAdditionalData?.accountTier;
if (accountTier === 'premium') {
// Premium customers get warm transfer to dedicated rep
const assignedRep = await getAssignedRep(customerId);
return res.json({
transferTo: assignedRep.phone,
transferType: 'warm',
briefing: `Premium customer ${customerId}. Reason: ${transferReason}`
});
}
// Standard customers get cold transfer to queue
return res.json({
transferTo: '+1-555-0100',
transferType: 'cold'
});
} catch (error) {
console.error('Transfer webhook error:', error);
// Fallback to default support line
return res.json({
transferTo: '+1-555-0100',
transferType: 'cold'
});
}
}
// Tool webhook handler - execute functions
async function handleToolWebhook(payload, res) {
const { toolName, arguments: args, callAdditionalData } = payload;
try {
switch (toolName) {
case 'check_account_balance':
const balance = await getAccountBalance(
args.customerId,
args.accountType
);
return res.json(balance);
case 'schedule_callback':
const scheduled = await scheduleCallback(
callAdditionalData?.customerId,
args.preferredTime
);
return res.json({ success: true, scheduledTime: scheduled });
case 'process_refund':
const refund = await processRefund(
args.orderId,
args.amount
);
return res.json(refund);
default:
return res.json({ error: `Unknown tool: ${toolName}` });
}
} catch (error) {
console.error(`Tool ${toolName} error:`, error);
return res.json({ error: error.message });
}
}
// Main webhook endpoint
app.post('/webhooks/blackbox', async (req, res) => {
const payload = req.body;
console.log(`Webhook received: ${payload.type}, callId: ${payload.callId}`);
switch (payload.type) {
case 'StartWebHookPayload':
return handleStartWebhook(payload, res);
case 'CompletedWebHookPayload':
await handleCompletedWebhook(payload);
return res.status(200).send('OK');
case 'FailedWebHookPayload':
await handleFailedWebhook(payload);
return res.status(200).send('OK');
case 'CallDeadLineWebHookPayload':
console.log(`Call ${payload.callId} canceled: ${payload.reasonMessage}`);
return res.status(200).send('OK');
case 'TransferWebHookPayload':
return handleTransferWebhook(payload, res);
case 'ToolWebHookPayload':
return handleToolWebhook(payload, res);
default:
console.warn(`Unknown webhook type: ${payload.type}`);
return res.status(200).send('OK');
}
});
// Health check
app.get('/health', (req, res) => res.status(200).send('OK'));
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook server running on port ${PORT}`);
});