> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kirafin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate signatures

> Prove a delivery came from Kira before you act on it.

Every delivery carries a signature. Verify it before you trust the payload — your endpoint is a public URL, and anything on the internet can post to it.

## The header

```
x-signature-sha256: <hex digest>
```

It is an **HMAC-SHA256** of the raw request body, keyed with your webhook secret, encoded as **hexadecimal**.

Kira gives you the secret when your endpoint is registered. Keep it out of your source tree, the same as your API key.

## Verifying it

Compute the same digest over the body you received and compare it with the header.

<CodeGroup>
  ```javascript Node.js theme={null}
  import crypto from 'node:crypto';

  function isFromKira(rawBody, headerValue, secret) {
    const expected = crypto
      .createHmac('sha256', secret)
      .update(rawBody)
      .digest('hex');

    const a = Buffer.from(expected, 'utf8');
    const b = Buffer.from(headerValue ?? '', 'utf8');

    return a.length === b.length && crypto.timingSafeEqual(a, b);
  }
  ```

  ```python Python theme={null}
  import hashlib
  import hmac

  def is_from_kira(raw_body: bytes, header_value: str, secret: str) -> bool:
      expected = hmac.new(
          secret.encode(), raw_body, hashlib.sha256
      ).hexdigest()
      return hmac.compare_digest(expected, header_value or "")
  ```
</CodeGroup>

## Two things that break verification

**Sign the raw body, not a re-serialised object.** If your framework parses the JSON and you re-encode it to verify, a different key order or spacing produces a different digest and every delivery fails. Capture the raw bytes before parsing.

**Compare in constant time.** `crypto.timingSafeEqual` and `hmac.compare_digest` above exist for this. A plain `===` on a secret-derived value leaks information about it.

## When it does not match

Reject the request and answer an error. Do not process the payload, and do not retry on your side — a mismatched signature means the delivery did not come from Kira, or the body was altered on the way.
