Skip to content

Webhooks API

Manage webhook endpoints for receiving real-time event notifications.

List Webhooks

http
GET /api/v1/webhooks

Response

json
{
  "data": [
    {
      "id": "wh_123",
      "url": "https://your-app.com/webhooks/converra",
      "events": ["optimization.completed", "prompt.updated"],
      "description": "Production webhook",
      "status": "active",
      "createdAt": "2025-01-15T10:00:00Z"
    }
  ]
}

Create Webhook

http
POST /api/v1/webhooks

Request Body

json
{
  "url": "https://your-app.com/webhooks/converra",
  "events": ["optimization.completed", "prompt.updated", "insights.generated"],
  "description": "Production webhook"
}

Required Fields

FieldTypeDescription
urlstringHTTPS endpoint URL
eventsstring[]Events to subscribe to

Optional Fields

FieldTypeDescription
descriptionstringHuman-readable description

Response

json
{
  "id": "wh_456",
  "url": "https://your-app.com/webhooks/converra",
  "events": ["optimization.completed", "prompt.updated", "insights.generated"],
  "secret": "whsec_abc123...",
  "status": "active",
  "createdAt": "2025-01-20T14:30:00Z"
}

Save Your Secret

The secret is only returned once at creation. Store it securely for signature verification.

Status: 201 Created


Delete Webhook

http
DELETE /api/v1/webhooks/:id

Response

json
{
  "success": true,
  "message": "Webhook deleted"
}

Status: 200 OK


Available Events

EventDescriptionPayload
prompt.updatedPrompt content changed{ promptId, promptName, updateType, variantId?, appliedAt }
prompt.deletedPrompt was deleted{ promptId, deletedAt }
optimization.startedOptimization began{ optimizationId, promptId, status, settings, startedAt }
optimization.completedOptimization finished{ optimizationId, promptId, results, duration, completedAt }
optimization.stoppedOptimization stopped manually{ optimizationId, promptId, reason, stoppedAt }
insights.generatedNew insights available{ conversationId, promptId, insightsId, summary, sentiment }
conversation.createdNew conversation logged{ conversationId, promptId, status, createdAt }

Webhook Payload Format

All webhook payloads follow this structure:

json
{
  "id": "evt_789",
  "type": "optimization.completed",
  "timestamp": "2025-01-20T14:30:00Z",
  "data": {
    "optimizationId": "opt_456",
    "promptId": "prompt_123",
    "results": {
      "winner": "variant_2",
      "improvementPercentage": 15.3
    },
    "duration": 847,
    "completedAt": "2025-01-20T14:30:00Z"
  }
}

Signature Verification

All webhooks include an X-Converra-Signature header for verification.

Verification Process

  1. Get the raw request body (not parsed JSON)
  2. Compute HMAC-SHA256 using your webhook secret
  3. Compare with the signature header

Example (Node.js)

typescript
import crypto from 'crypto';

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Example (Express)

typescript
app.post('/webhooks/converra', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-converra-signature'] as string;
  
  if (!verifyWebhook(req.body.toString(), signature, process.env.WEBHOOK_SECRET!)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const event = JSON.parse(req.body.toString());
  // Handle event...
  
  res.status(200).json({ received: true });
});

Use Raw Body

Always use the raw request body for signature verification. Parsed JSON may have different formatting.


Retry Policy

Failed webhook deliveries are retried with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the webhook is marked as failing and notifications are paused.


SDK Usage

typescript
// List webhooks
const webhooks = await converra.webhooks.list();

// Create webhook
const webhook = await converra.webhooks.create({
  url: 'https://your-app.com/webhooks/converra',
  events: ['optimization.completed', 'prompt.updated'],
  description: 'Production webhook'
});

// Save the secret!
console.log('Webhook secret:', webhook.secret);

// Delete webhook
await converra.webhooks.delete('wh_123');

Error Responses

Invalid URL

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid webhook URL",
    "details": {
      "url": "Must be a valid HTTPS URL"
    }
  }
}

Webhook Not Found

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Webhook not found"
  }
}