# Verifying requests

> How every call from Storeware to your app is signed, and how to check it.

Source: https://storeware.ai/docs/webhooks/verifying

Every request Storeware makes to your app (webhooks, tools, knowledge and storefront blocks) is signed the same way. Verify `v2`, and never accept `v1` alone: it signs no kind, so a webhook captured on its way to you could be replayed at your tool endpoint.

Not writing JavaScript? [Verifying in other languages](https://storeware.ai/docs/webhooks/other-languages) has the same checks in Python, PHP, Go and Ruby, and test vectors to run them against.

## Verifying one

Every delivery is signed with the secret shown once when you created the
endpoint. Compare it in constant time and reject anything you cannot verify:
an unverified webhook is an instruction from anybody who guessed your URL.

```js
import { verifyWebhook } from '@storeware/plugin-sdk/webhooks';

// The SDK does this for you, and is the recommended route. It throws on
// anything it cannot verify, so a forgotten check cannot pass silently.
const event = verifyWebhook({
  secret: SECRET,
  rawBody,
  signatureHeader: req.get('storeware-signature'),
});
```

One header, `storeware-signature`, carrying the time and two signatures:

```
storeware-signature: t=1754400131,v1=9f2ae1c4...,v2=41c07b2e...
storeware-kind: webhook
```

`v2` is `HMAC-SHA256` over `` `${t}.${kind}.${rawBody}` `` with your secret,
hex encoded, where `kind` is `webhook` for a webhook. The same secret signs
every call Storeware makes to an app (webhooks, tool calls, knowledge requests,
storefront blocks), and the kind inside `v2` is what stops a request captured on
its way to one of your endpoints from verifying at another. `v1` is the older
`` `${t}.${rawBody}` `` signature, still sent so integrations written against it
keep working; it says nothing about the kind, so check `v2` in anything new.

If you would rather not take the dependency, compute `v2` yourself and compare
in constant time, and reject anything where `t` is more than five minutes old:
a signature stays valid forever without that check, so a captured request can
be replayed indefinitely.

Verify against the **raw body**, before any JSON parsing. Re-serialising an
object does not reproduce the bytes that were signed, and a handler that parses
first will fail every signature and eventually be "fixed" by removing the check.
