Appearance
Webhooks
Receive real-time notifications when events occur in Converra.
Setup
1. Register a Webhook
typescript
const webhook = await converra.webhooks.create({
url: 'https://your-app.com/webhooks/converra',
events: ['optimization.completed', 'prompt.updated', 'insights.generated'],
description: 'Production webhook'
});
// Save the secret - only shown once!
console.log('Webhook secret:', webhook.secret);2. Create a Handler
typescript
import { createWebhookHandler } from 'converra';
const handler = createWebhookHandler({
secret: process.env.CONVERRA_WEBHOOK_SECRET!,
onPromptUpdated: (data) => {
console.log(`Prompt ${data.promptId} updated`);
},
onOptimizationCompleted: (data) => {
console.log(`Optimization complete: ${data.results.improvementPercentage}% improvement`);
},
});3. Register the Endpoint
Express:
typescript
app.post('/webhooks/converra', express.raw({ type: 'application/json' }), async (req, res) => {
const result = await handler(req.body, req.headers['x-converra-signature']);
res.status(result.success ? 200 : 400).json(result);
});Next.js App Router:
typescript
export async function POST(req: Request) {
const body = await req.text();
const signature = req.headers.get('x-converra-signature') || '';
const result = await handler(body, signature);
return Response.json(result, { status: result.success ? 200 : 400 });
}Available Events
| Event | Description |
|---|---|
prompt.updated | Prompt content changed (e.g., variant applied) |
prompt.deleted | Prompt was deleted |
optimization.started | Optimization process began |
optimization.completed | Optimization finished with results |
optimization.stopped | Optimization was manually stopped |
insights.generated | New insights available for a conversation |
conversation.created | New conversation logged |
Handler Options
typescript
const handler = createWebhookHandler({
secret: process.env.CONVERRA_WEBHOOK_SECRET!,
// Prompt events
onPromptUpdated: (data) => {
// data: { promptId, promptName, updateType, variantId?, appliedAt }
},
onPromptDeleted: (data) => {
// data: { promptId, deletedAt }
},
// Optimization events
onOptimizationStarted: (data) => {
// data: { optimizationId, promptId, status, settings, startedAt }
},
onOptimizationCompleted: (data) => {
// data: { optimizationId, promptId, results, duration, completedAt }
},
onOptimizationStopped: (data) => {
// data: { optimizationId, promptId, reason, stoppedAt }
},
// Insight events
onInsightsGenerated: (data) => {
// data: { conversationId, promptId, insightsId, summary, sentiment }
},
// Conversation events
onConversationCreated: (data) => {
// data: { conversationId, promptId, status, createdAt }
},
// Catch-all handler
onEvent: (event, data, metadata) => {
console.log(`Received ${event}`, data);
},
// Error handler
onError: (error, event) => {
console.error(`Webhook error for ${event}:`, error);
},
});Signature Verification
The SDK automatically verifies webhook signatures using HMAC-SHA256. Always pass the raw request body (not parsed JSON) to ensure verification works correctly.
typescript
// Correct - raw body
app.post('/webhooks/converra', express.raw({ type: 'application/json' }), handler);
// Wrong - parsed body will fail signature verification
app.post('/webhooks/converra', express.json(), handler);Common Pattern: Cache Invalidation
typescript
const handler = createWebhookHandler({
secret: process.env.CONVERRA_WEBHOOK_SECRET!,
onPromptUpdated: (data) => {
converra.cache.invalidate(data.promptId);
console.log(`Cache invalidated for prompt ${data.promptId}`);
},
});