Webhooks API

Subscribe to real-time event notifications.

Overview

Webhooks push real-time event notifications to your external systems. Instead of polling the API, register a URL and Katura will POST event data to it when things happen.

Available webhook events

  • order.created β€” new order placed
  • order.updated β€” order status changed
  • order.cancelled β€” order cancelled
  • customer.created β€” new customer registered
  • product.created β€” new product added
  • product.updated β€” product modified
  • inventory.low β€” stock level below threshold

Registering a webhook

  1. Go to Settings β†’ Developer β†’ Webhooks
  2. Click Add Webhook
  3. Enter the endpoint URL and select the events to subscribe to
  4. Save β€” Katura will begin sending events immediately

Webhook security

Each webhook includes a signature header for verification. Always validate the signature before processing webhook data to prevent spoofing.

Payload shape

POST https://your-app.example.com/hooks/katura
Content-Type: application/json
X-Katura-Event: order.paid
X-Katura-Delivery: dlv_01HX...
X-Katura-Timestamp: 1714152043
X-Katura-Signature: t=1714152043,v1=8a3c...

{
  "event": "order.paid",
  "data": {
    "id": "ord_01HX...",
    "number": "1042",
    "total": "5184.00",
    "currency": "USD",
    "customer": { "id": "cus_01HX...", "email": "alice@example.com" },
    "paidAt": "2026-04-26T18:40:43.123Z"
  }
}

Signature verification

Verify X-Katura-Signature using HMAC-SHA256 of {timestamp}.{rawBody}with your webhook secret. Reject anything older than 5 minutes to prevent replay.

// Node.js / TypeScript
import crypto from "node:crypto";

export function verifyKaturaSignature(
  rawBody: string,
  header: string,
  secret: string,
): boolean {
  const parts = Object.fromEntries(
    header.split(",").map(kv => kv.split("="))
  );
  const timestamp = Number(parts.t);
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signed = `${timestamp}.${rawBody}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(signed)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(parts.v1, "hex")
  );
}

Delivery & retries

Katura expects a 2xx response within 10 seconds. Anything else triggers an exponential-backoff retry: 1 min, 5 min, 30 min, 2 hr, 12 hr, then daily for 7 days. After that the delivery is marked failed and the receiving endpoint gets a summary email.

Replay any delivery from Settings β†’ Developer β†’ Webhooks β†’ Deliveries. Each delivery shows headers, body, response status, response body, and timing.

Best practices

  • Acknowledge fast, work later. Return 200 immediately, queue the heavy work.
  • Idempotent handlers. Use X-Katura-Delivery as a dedup key β€” the same event will retry.
  • One secret per endpoint. Rotating one doesn't affect others.
  • Don't trust event order. order.paid can arrive before order.created in rare network conditions; design for it.

Was this article helpful?

Webhooks API β€” Real-Time Event Notifications | K99