api-reference
Webhooks API

Webhooks API

Webhooks allow you to build or set up integrations that subscribe to certain events on Kortexa. When one of those events is triggered, we'll send a HTTP POST payload to the webhook's configured URL.

Webhooks are crucial for asynchronous workflows, such as being notified when a large PDF file has finished indexing (file.indexed) or when an AI Assistant completes a long-running generation (thread.message.created).

Register a Webhook

POST /v1/webhooks

Registers a new HTTPS endpoint to receive live events.

Request Body

{
  "url": "https://your-domain.com/webhooks/kortexa",
  "events": ["file.indexed", "thread.message.created"]
}

Example Response

{
  "data": {
    "id": "wh_abc123",
    "url": "https://your-domain.com/webhooks/kortexa",
    "events": ["file.indexed", "thread.message.created"],
    "secret": "whsec_9b72a...", 
    "isActive": true,
    "createdAt": "2024-03-05T14:22:00Z"
  }
}

⚠️ Important: The secret is only returned once during creation. Store it safely! You will need it to verify the cryptographic signatures of incoming webhook payloads.

Verifying Webhook Signatures

Kortexa signs the webhook events it sends to your endpoints by including a signature in each event's Kortexa-Signature header. This allows you to verify that the events were sent by Kortexa, not by a third party.

The Kortexa-Signature header contains a timestamp and a signature.

Kortexa-Signature: t=1614556800000,v1=5257a869e7ecebea0d1b1a3d1326442be...

Verification Step-by-Step (Using the Official SDK)

We strongly recommend using the official @kortexa/sdk for Node.js to verify webhook signatures. It automatically parses headers and prevents timing attacks.

npm install @kortexa/sdk
import { KortexaClient } from '@kortexa/sdk';
 
const kortexa = new KortexaClient({ apiKey: process.env.KORTEXA_API_KEY });
 
// Express.js Example Handler
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['kortexa-signature'];
  
  try {
    const event = kortexa.webhooks.constructEvent(
      req.body.toString(), 
      signature, 
      process.env.KORTEXA_WEBHOOK_SECRET
    );
    
    console.log("Verified Kortexa Event Received!", event);
    res.json({ received: true });
  } catch (err) {
    res.status(400).send(`Webhook Error: ${err.message}`);
  }
});

Manual Verification (Fallback)

import crypto from 'crypto';
 
function verifySignature(payloadString, header, secret) {
  const parts = header.split(',');
  const timestamp = parts.find(p => p.startsWith('t=')).split('=')[1];
  const signature = parts.find(p => p.startsWith('v1=')).split('=')[1];
 
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payloadString)
    .digest('hex');
 
  if (signature !== expectedSignature) {
    throw new Error("Invalid signature");
  }
}