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

# Webhook Security

> Learn how Moralis secures webhook delivery using request signatures, and how to verify webhook authenticity in your backend.

## Overview

All Moralis webhooks are **cryptographically signed** to ensure authenticity and integrity.

By verifying each webhook signature, you can be confident that:

* The request was sent by Moralis
* The payload was not tampered with
* Your application is protected against spoofed requests

Signature verification is **strongly recommended** for all production environments.

***

## How Webhook Signing Works

Every webhook request includes a signature in the HTTP headers:

```text theme={null}
x-signature
```

This signature is generated by:

1. Serializing the webhook payload
2. Appending your account’s secret
3. Computing a Keccak-256 hash (via `web3.utils.sha3`)

Conceptually:

```javascript theme={null}
signature = sha3(JSON.stringify(body) + secret)
```

The generated signature is then sent with the webhook request.

***

## What Is the Secret Key?

The **secret key** is a Streams-specific credential associated with your Moralis account.

* It is **not** your API key
* It is used **only** for webhook verification
* It can be retrieved via the Streams settings endpoint

***

## Verifying Webhook Signatures

To verify a webhook:

1. Read the `x-signature` header
2. Recompute the signature using the request body and your secret
3. Compare the two values
4. Reject the request if they do not match

Verification should happen **before** processing the payload.

***

## Example: Node.js (Express)

```javascript theme={null}
import { Web3 } from "web3";

function verifySignature(req, secret) {
  const providedSignature = req.headers["x-signature"];
  if (!providedSignature) {
    throw new Error("Missing signature");
  }

  const web3 = new Web3();
  const expectedSignature = web3.utils.sha3(
    JSON.stringify(req.body) + secret
  );

  if (expectedSignature !== providedSignature) {
    throw new Error("Invalid signature");
  }
}
```

Use this check at the start of your webhook handler.

For handling test webhooks safely, explore [Test Webhooks](/streams/webhooks/test-webhooks).

***

## Security Best Practices

### Always verify signatures

Do not trust:

* Source IP
* User-Agent headers
* Payload structure alone

***

### Use HTTPS

Webhook endpoints must be served over HTTPS to prevent interception or replay.

***

### Keep handlers lightweight

Slow responses can cause retries or queue buildup. Explore [Webhook Delivery](/streams/webhooks/webhook-delivery) to learn how to handle this.

***

### Make handlers idempotent

Retries may result in duplicate payloads. Read more about [Retries & Replays](/streams/webhooks/retries-and-replays).

***

## What Happens If Verification Fails?

If your endpoint:

* Rejects the request (non-2xx)
* Throws an error
* Times out

Then:

* The webhook is considered failed
* Automatic retries will occur
* The stream’s success rate may drop

Read [Error Handling](/streams/streams-concepts/error-handling) for more on failure handling.

***

## Relationship to Other Webhook Concepts

| Topic                    | Page                                                                       |
| :----------------------- | :------------------------------------------------------------------------- |
| Delivery guarantees      | [**Webhook Delivery**](/streams/webhooks/webhook-delivery)                 |
| Confirmed vs unconfirmed | [**Confirmation & Finality**](/streams/webhooks/confirmation-and-finality) |
| Test requests            | [**Test Webhooks**](/streams/webhooks/test-webhooks)                       |
| Retries & recovery       | [**Retries & Replays**](/streams/webhooks/retries-and-replays)             |
| Failure states           | [**Error Handling**](/streams/streams-concepts/error-handling)             |
