Kilo Docs

Docs / Webhooks/ Webhooks

Webhooks

Updated Aug 9, 2026

When something important happens, Kilo POSTs JSON to your HTTPS URL.

Why webhooks feel “faster than the HTTP response”

Your POST /deliveries returns as soon as Kilo saves the job.

Separately, we enqueue the webhook with Upstash QStash, so:

  • Your create API stays fast.
  • Your webhook URL is called with retries if it is down.
  • You still verify that the POST really came from Kilo.

Create an endpoint

  1. Dashboard → Settings → API & Webhooks.
  2. Add endpoint with an https:// URL.
  3. Choose events (start with all delivery events).
  4. Copy the whsec_... signing secret (shown once).

Events

Event When
delivery.created After a successful create (API or other sources that emit)
delivery.cancelled Delivery cancelled
delivery.status_changed Status moved (when emitted)
delivery.updated General update (when emitted)
delivery.completed Delivery completed (when emitted)

Headers on every webhook

Header Meaning
Content-Type application/json
Kilo-Signature t=<unix>,v1=<hex>
Kilo-Event Event name

Verify the signature (do this for real)

  1. Read Kilo-Signature.
  2. Split into t and v1.
  3. Reject if t is older than 5 minutes.
  4. Compute HMAC-SHA256 of ${t}.${rawBody} using your whsec_... secret.
  5. Compare hex digests in constant time.

Example Node.js:

import crypto from "node:crypto";

function verify(secret, rawBody, header) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => {
      const [k, ...rest] = p.split("=");
      return [k, rest.join("=")];
    }),
  );
  const t = Number(parts.t);
  const v1 = parts.v1;
  if (!t || !v1) return false;
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Respond

Return HTTP 2xx quickly. Do heavy work in your own queue after verifying the signature.

Handle customer messages yourself

Many bots already own the conversation with the customer. In that case:

  1. Dashboard → Settings → Notifications → turn Customer delivery messages off.
  2. Subscribe to the events above (especially delivery.status_changed / delivery.completed).
  3. Send WhatsApp / SMS / push from your product when those webhooks arrive.

Kilo will not send tracking links, pickup/nearby/arrived updates, or completion/feedback WhatsApps to your customers while that setting is off. Delivery OTPs and rider notifications still work.