All guides

Webhooks

Receive real-time event notifications from Panacea in your own backend systems.

2 min read282 words

Webhooks let Panacea push real-time event notifications to your own server. Instead of polling the API, your backend receives an HTTP POST when something happens.

Opening Webhooks

Go to Settings -> Webhooks. Requires admin or trainer role.

Creating a webhook

  1. Click New webhook.
  2. Enter the endpoint URL — a publicly accessible HTTPS URL on your server.
  3. Select the events you want to subscribe to.
  4. Click Save.

Panacea sends a test event immediately. If your server returns a 200 OK, the webhook is active.

Available events

Event Triggered when
entry.created A wiki entry is created
entry.updated A wiki entry is edited
entry.deleted A wiki entry is deleted
review.requested A new review queue proposal is created
review.approved A proposal is approved
review.rejected A proposal is rejected
ingest.completed An ingestion run completes successfully
ingest.failed An ingestion run fails
handover.requested A session is escalated to a human agent
handover.claimed An agent claims an escalation
handover.resolved An escalation is marked resolved
session.closed A session is closed

Webhook payload format

All events share the same envelope:

{
  "event": "handover.requested",
  "tenantId": "ten_xxxxxxxxxxxx",
  "timestamp": "2026-06-25T18:43:09.703Z",
  "data": {
    "id": "esc_xxxxxxxxxxxx",
    "sessionId": "sess_xxxxxxxxxxxx",
    "trigger": "CUSTOMER_REQUESTED",
    "status": "pending"
  }
}

Verifying webhook signatures

Every webhook request includes an X-Panacea-Signature header with the format sha256=<HMAC-SHA256>, signed with your webhook secret.

import { createHmac } from 'crypto'

export async function POST(req: Request) {
  const body = await req.text()
  const signature = req.headers.get('X-Panacea-Signature')
  const expected = 'sha256=' + createHmac('sha256', process.env.PANACEA_WEBHOOK_SECRET!)
    .update(body)
    .digest('hex')

  if (signature !== expected) {
    return new Response('Unauthorized', { status: 401 })
  }

  const event = JSON.parse(body)
  // handle event...
  return new Response('OK')
}

Retry behaviour

If your endpoint returns a non-2xx status or times out (>10 seconds), Panacea retries 3 times with increasing delays: 100 ms, 1 s, and 5 s. After all retries fail the event is marked failed. Each delivery attempt uses the same idempotency ID — safe to replay from the webhook detail view.

Testing webhooks locally

Use a tool like ngrok to expose your local development server:

ngrok http 3000
# Forwarding: https://abc123.ngrok.io -> http://localhost:3000

Use the ngrok URL as your webhook endpoint during development.

Related guides