Webhooks

Signed events pushed to your server the moment Kuno finishes processing a note — no polling.

Webhooks push a JSON event to your server the moment Kuno finishes a processing step. Every delivery is signed with an endpoint-specific secret so your server can verify it really came from Kuno.

Register an endpoint

  1. Add the webhook. In the app: Settings → Developer settings → Webhooks → "Add webhook". Enter your HTTPS payload URL and pick the events (up to 10 endpoints per account).
  2. Store the signing secret. The secret (kuno_whsec_…) is shown exactly once — store it next to your endpoint.
  3. Send a test event. Trigger a test from the endpoint's detail sheet — Kuno shows your server's live HTTP status.

From the same detail sheet you can also pause/resume the endpoint, rotate the secret, inspect recent deliveries, or delete the webhook.

Events

TypeFires whenPayload highlights
transcription.completed A transcript is ready. data.transcript.segments — speaker, text, timings.
summary.completed A summary is ready. data.summary — title, body, key points, decisions, action items.
recording.processed All processing for a note finished successfully. data.recording only — a light "done" signal.
ping You send a test from the app. data.webhookId.

Every event also carries data.recording with the note's id, title, status, duration, and language.

Envelope

{
  "id": "evt_5f0c4c8e-…",
  "type": "summary.completed",
  "createdAt": "2026-07-04T08:12:31.000Z",
  "data": {
    "recording": { "id": "…", "title": "Standup notes", "status": "processed",
                   "durationSeconds": 1260, "languageCode": "de" },
    "summary": { "id": "…", "title": "Standup — July 4", "body": "…",
                 "keyPoints": ["…"], "decisions": ["…"],
                 "actionItems": ["…"] }
  }
}

Delivery headers

HeaderValue
X-Kuno-EventThe event type.
X-Kuno-Event-IdThe envelope id — deduplicate on this.
X-Kuno-TimestampUnix seconds when the delivery was signed.
X-Kuno-Signaturev1=<hex HMAC-SHA256>
User-AgentKuno-Webhooks/1.0

Verify the signature

The signed string is {timestamp}.{rawBody} — the raw request bytes, not re-serialized JSON. Compare in constant time, and reject timestamps older than ~5 minutes to blunt replay:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, timestamp, rawBody, signatureHeader) {
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected =
    "v1=" +
    createHmac("sha256", secret)
      .update(`${timestamp}.${rawBody}`)
      .digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader);
  return a.length === b.length && timingSafeEqual(a, b);
}

Delivery & retries

  • HTTP POST, JSON body; respond with any 2xx within 10 seconds.
  • Failed deliveries are retried twice (about 2 s and then 10 s later) — three attempts total. Delivery is at-least-once: deduplicate on X-Kuno-Event-Id.
  • After 20 consecutive failures the endpoint is paused automatically; the app shows why, and you can resume it after fixing your server.
  • Test events count too: a manually triggered test event runs through the same failure counter as real deliveries. A failed test moves the endpoint closer to auto-pause, and a successful test resets the counter to zero — which can mask a flaky setup if you only test occasionally.

Security: endpoints must be public HTTPS URLs — private and internal hosts are rejected. Rotating the secret re-signs all future deliveries immediately, so update your server first. Webhook payloads contain your note content — treat your endpoint like any system that stores personal data.

Still need help?

We usually reply within one business day.