Webhooks
Subscribe to real-time events from Kakunin — certificate issuance, revocation, high-risk alerts, and more.
Overview
Kakunin can push events to your systems in real time via webhooks. This is how you build reactive workflows: auto-blocking a revoked agent at your gateway, alerting your compliance team on high-risk events, or syncing certificate status to your internal registry.
Registering a Webhook
POST /v1/webhooks{
"url": "https://your-system.com/webhooks/kakunin",
"events": ["certificate.revoked", "agent.high_risk"],
"description": "Production compliance handler"
}Response 201:
{
"data": {
"id": "uuid",
"url": "https://your-system.com/webhooks/kakunin",
"events": ["certificate.revoked", "agent.high_risk"],
"secret": "whsec_xxxxxxxxxxxxxxxx",
"active": true,
"created_at": "2026-05-17T00:00:00Z"
}
}The secret is shown once at creation. Store it securely — you need it to verify webhook signatures.
Event Types
| Event | Trigger |
|---|---|
certificate.issued | New X.509 certificate issued for an agent |
certificate.revoked | Certificate explicitly revoked |
certificate.expired | Certificate passed its expires_at |
agent.high_risk | Agent risk score crossed ≥ 0.85 threshold |
agent.created | New agent registered |
agent.suspended | Agent status changed to suspended |
Webhook Payload
All events share a common envelope:
{
"id": "evt_uuid",
"event": "certificate.revoked",
"created_at": "2026-05-17T10:00:00Z",
"data": {
"serial_number": "abc123",
"agent_id": "uuid",
"revocation_reason": "Anomalous behaviour detected",
"revoked_at": "2026-05-17T10:00:00Z"
}
}Verifying Signatures
Every webhook request includes an X-Kakunin-Signature header. Verify it to confirm the payload came from Kakunin.
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(`sha256=${expected}`)
);
}
// In your webhook handler:
const raw = await req.text();
const sig = req.headers.get('x-kakunin-signature') ?? '';
if (!verifyWebhook(raw, sig, process.env.KAKUNIN_WEBHOOK_SECRET!)) {
return new Response('Unauthorized', { status: 401 });
}Delivery and Retries
Kakunin delivers webhooks via QStash with the following guarantees:
- 3 automatic retries on non-2xx responses
- Exponential backoff between retries (1s, 10s, 100s)
- Delivery timeout: 30 seconds per attempt
- Delivery history visible at
GET /v1/webhooks/{id}/deliveries
Your endpoint must return a 2xx response within 30 seconds. Return 200 immediately and process asynchronously if your handler takes longer.
Listing and Managing Webhooks
GET /v1/webhooks # list all webhooks
GET /v1/webhooks/{id} # get one webhook
PATCH /v1/webhooks/{id} # update url, events, or active status
DELETE /v1/webhooks/{id} # delete webhook
GET /v1/webhooks/{id}/deliveries # delivery history