Cost Katana webhooks notify you about important events in real-time. Perfect for monitoring costs, tracking usage, and automating responses.
import { ai, configure } from 'cost-katana';
// Configure webhook endpoint
await configure({
apiKey: 'dak_your_key',
webhookUrl: 'https://your-api.com/webhooks/costkatana'
});
// Use normally - webhooks fire automatically
await ai('gpt-4', 'Expensive request');
// Webhook fires if cost threshold exceededcost.alert- Cost alert triggeredcost.threshold_exceeded- Threshold exceededcost.spike_detected- Unusual cost spikebudget.warning- Approaching budget limitbudget.exceeded- Budget limit exceeded
optimization.completed- Optimization finishedoptimization.suggested- New suggestions availablesavings.milestone_reached- Savings milestone hit
usage.spike_detected- Usage spike detectedusage.pattern_changed- Pattern change detected
{
"event_id": "evt_123",
"event_type": "cost.alert",
"occurred_at": "2025-01-15T10:30:00Z",
"severity": "high",
"title": "Cost threshold exceeded",
"description": "Monthly cost exceeded $500",
"metrics": {
"current": 550,
"threshold": 500,
"unit": "USD"
},
"cost": {
"amount": 550,
"currency": "USD",
"period": "monthly"
}
}import express from 'express';
import { verifyWebhookSignature } from 'cost-katana';
const app = express();
app.use(express.json());
app.post('/webhooks/costkatana', (req, res) => {
const signature = req.headers['x-costkatana-signature'];
const timestamp = req.headers['x-costkatana-timestamp'];
const payload = JSON.stringify(req.body);
// Verify signature
const isValid = verifyWebhookSignature(
payload,
timestamp,
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const event = req.body;
// Handle events
switch (event.event_type) {
case 'cost.alert':
console.log('Cost alert:', event.description);
// Send Slack notification
break;
case 'budget.exceeded':
console.log('Budget exceeded:', event.metrics);
// Send email alert
break;
case 'optimization.suggested':
console.log('Optimization available:', event.description);
// Log suggestion
break;
}
res.status(200).send('OK');
});
app.listen(3000);// app/api/webhooks/costkatana/route.ts
import { verifyWebhookSignature } from 'cost-katana';
export async function POST(request: Request) {
const signature = request.headers.get('x-costkatana-signature');
const timestamp = request.headers.get('x-costkatana-timestamp');
const body = await request.text();
const isValid = verifyWebhookSignature(
body,
timestamp,
signature,
process.env.WEBHOOK_SECRET!
);
if (!isValid) {
return Response.json({ error: 'Invalid signature' }, { status: 401 });
}
const event = JSON.parse(body);
// Handle event
console.log('Webhook received:', event.event_type);
return Response.json({ received: true });
}app.post('/webhooks/costkatana', (req, res) => {
const event = req.body;
if (event.event_type === 'cost.alert') {
// Send Slack notification
sendSlackMessage({
channel: '#cost-alerts',
text: `🚨 ${event.title}: $${event.cost.amount}`,
details: event.description
});
}
res.status(200).send('OK');
});app.post('/webhooks/costkatana', (req, res) => {
const event = req.body;
if (event.event_type === 'budget.warning') {
const percentage = (event.metrics.current / event.metrics.threshold) * 100;
console.log(`⚠️ Budget at ${percentage}%`);
// Take action
if (percentage > 90) {
// Disable non-critical AI features
disableOptionalAIFeatures();
}
}
res.status(200).send('OK');
});app.post('/webhooks/costkatana', (req, res) => {
const event = req.body;
if (event.event_type === 'optimization.suggested') {
// Log optimization opportunity
console.log('💡 Optimization available:');
console.log(event.description);
console.log(`Potential savings: $${event.metrics.estimated_savings}`);
// Auto-apply if savings > $10/month
if (event.metrics.estimated_savings > 10) {
applyOptimization(event.optimization_id);
}
}
res.status(200).send('OK');
});All webhooks include a cryptographic signature:
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
timestamp: string,
signature: string,
secret: string
): boolean {
const signaturePayload = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signaturePayload)
.digest('hex');
return `sha256=${expected}` === signature;
}-
Always verify signatures
if (!verifyWebhookSignature(...)) { return res.status(401).send('Invalid'); }
-
Respond quickly (< 5 seconds)
res.status(200).send('OK'); processWebhookAsync(event); // Process in background
-
Handle duplicates with event_id
const processed = new Set(); if (processed.has(event.event_id)) { return res.status(200).send('Already processed'); } processed.add(event.event_id);
-
Implement retry logic
async function processWebhook(event: any) { const maxRetries = 3; for (let i = 0; i < maxRetries; i++) { try { await handleEvent(event); return; } catch (error) { if (i === maxRetries - 1) throw error; await sleep(1000 * Math.pow(2, i)); } } }
import { ai } from 'cost-katana';
async function sendToSlack(message: string) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
body: JSON.stringify({ text: message })
});
}
// In your webhook handler
if (event.event_type === 'cost.alert') {
await sendToSlack(
`🚨 Cost Alert: ${event.description}\nAmount: $${event.cost.amount}`
);
}import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransporter({...});
// In webhook handler
if (event.event_type === 'budget.exceeded') {
await transporter.sendMail({
to: 'admin@company.com',
subject: '⚠️ AI Budget Exceeded',
text: `Your AI budget has been exceeded.\nCurrent: $${event.cost.amount}\nLimit: $${event.metrics.threshold}`
});
}import { db } from './database';
// Log all webhook events
app.post('/webhooks/costkatana', async (req, res) => {
const event = req.body;
await db.webhookEvents.insert({
eventId: event.event_id,
eventType: event.event_type,
severity: event.severity,
timestamp: event.occurred_at,
data: event
});
res.status(200).send('OK');
});# Install ngrok
npm install -g ngrok
# Start your local server
node server.js
# Expose it
ngrok http 3000
# Use the ngrok URL in Cost Katana dashboard
# https://abc123.ngrok.io/webhooks/costkatana// Send test webhook
const testPayload = {
event_id: 'test_123',
event_type: 'cost.alert',
occurred_at: new Date().toISOString(),
severity: 'medium',
title: 'Test Alert',
description: 'This is a test',
cost: { amount: 100, currency: 'USD' }
};
await fetch('http://localhost:3000/webhooks/costkatana', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(testPayload)
});-
Check endpoint is accessible
curl -X POST https://your-api.com/webhooks/costkatana \ -H "Content-Type: application/json" \ -d '{"test": true}'
-
Verify webhook is active in dashboard
- Visit https://costkatana.com/settings/webhooks
- Check webhook status is "Active"
-
Check event subscriptions
- Ensure you're subscribed to the events you want
-
Use raw body for verification
app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf.toString(); } }));
-
Check secret matches
- Verify webhook secret in dashboard
- Ensure secret is correct in your code
Check your event subscriptions and filters:
// Make sure you're subscribed to the events
// Visit: https://costkatana.com/settings/webhooks- Documentation: https://docs.costkatana.com/webhooks
- Dashboard: https://costkatana.com/settings/webhooks
- GitHub: https://github.com/Hypothesize-Tech/costkatana-core
- Email: support@costkatana.com