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

# Verify Signature (validation_hash)

> How to verify webhook integrity.

Each webhook includes a `results.validation_hash` you can verify to ensure the payload hasn’t been tampered with.

## Hash composition

The `validation_hash` is a SHA-256 over the **string concatenation**:

```
amount + client_reference + payment_uuid + payment_reference
```

* `amount` - numeric amount from the original payment request
* `client_reference` - your unique transaction reference (same as `transaction_reference`)
* `payment_uuid` - Waftpay’s reference
* `payment_reference` - the payment reference received from the transaction

> The hash is generated on our side during notification building and included in the webhook payload. You can recompute it using the values you already know from your original request and the webhook body to cross-check integrity.

:::
For production-grade integrity, we recommend migrating to a HMAC with a **per-client secret** (provided via the dashboard/API) rather than a plain concatenated hash.
:::

## Examples

### Node.js (TypeScript)

```ts theme={null}
import crypto from "node:crypto";

function toFixedPlain(n: number) {
  // Ensure string format matches your canonical amount representation
  return Number(n).toString();
}

export function verifyValidationHash(
  amount: number,
  clientRef: string,
  paymentUuid: string,
  paymentReference: string,
  receivedHash: string
) {
  const payload = `${toFixedPlain(amount)}${clientRef}${paymentUuid}${paymentReference}`;
  const computed = crypto.createHash("sha256").update(payload).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(receivedHash));
}
```

### Java

```java theme={null}
MessageDigest md = MessageDigest.getInstance("SHA-256");
String payload = amount + clientRef + paymentUuid + paymentReference;
byte[] digest = md.digest(payload.getBytes(StandardCharsets.UTF_8));
String computed = DatatypeConverter.printHexBinary(digest).toLowerCase();
boolean ok = computed.equals(receivedHash);
```

### PHP

```php theme={null}
$payload = (string)$amount . $clientRef . $paymentUuid . $paymentReference;
$computed = hash('sha256', $payload);
$ok = hash_equals($computed, $receivedHash);
```
