Skip to main content
Every webhook delivery includes a x-klikit-signature header. You must verify it before processing the payload — otherwise anyone who knows your URL can forge orders.

The recipe

expected = hex( HMAC-SHA256( your_webhook_secret, raw_request_body ) )

if expected != x-klikit-signature: reject
Three things to keep straight:
  • HMAC-SHA256, not plain SHA-256. The secret is the key, the body is the message.
  • Raw request body, not the parsed-and-reserialised JSON. Any whitespace or key-order difference changes the bytes and breaks the hash.
  • Lowercase hex encoding, not base64.

Worked examples

const crypto = require("crypto");
const express = require("express");

const app = express();

// IMPORTANT: capture the raw body BEFORE JSON parsing.
app.use(express.json({
  verify: (req, _res, buf) => { req.rawBody = buf; },
}));

app.post("/webhooks/klikit", (req, res) => {
  const expected = crypto
    .createHmac("sha256", process.env.KLIKIT_WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest("hex");

  const given = req.get("x-klikit-signature") || "";
  const ok = given.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));

  if (!ok) return res.status(401).json({ error: "invalid signature" });
  res.status(200).json({ status: "received" });
});

Generating a test delivery yourself

To validate your verifier before klikit is wired up to your URL, build a test request locally:
SECRET="your-webhook-secret"
BODY='{"brand_id":1,"branch_id":2,"orders":[{"id":42}]}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST http://localhost:8080/webhooks/klikit \
  -H "Content-Type: application/json" \
  -H "x-klikit-event-id: test-$(uuidgen)" \
  -H "x-klikit-event-type: klikit.order.created.v2" \
  -H "x-klikit-signature: $SIG" \
  -d "$BODY"
Expected response: 200 {"status":"received"}. To confirm verification works, mangle the body or the signature and re-send. You should now get 401 {"error":"invalid signature"}.

Where to get your webhook_secret

Your klikit integration contact provides it during onboarding, alongside your partner API key. Don’t commit the secret. Rotate it via the operator if you suspect it’s been exposed.