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

# Configuration

> Set up and manage webhooks to receive real-time verification and AML event notifications from Dataspike.

Webhooks enable your application to receive **real-time event notifications** from the Dataspike platform.\
Instead of polling the API, you can register an endpoint that automatically receives updates for verification results, AML matches, and other key events.

> ⚡ **Use case:** Webhooks are essential for production integrations — they allow your systems to react immediately when verifications complete, AML matches occur, or applicants change status.

***

## 1. Understanding Webhooks

A **webhook** is an HTTP `POST` request sent by Dataspike to your configured endpoint whenever a specific event occurs.

Example flow:

1. You register a webhook URL (e.g. `https://api.yourdomain.com/dataspike/webhook`).
2. A verification completes on Dataspike.
3. Dataspike sends a signed POST request to your URL with the verification data.

Webhook payloads are sent as **JSON objects** and contain the event type, timestamp, and relevant entity data.

**Example payload:**

```json theme={null}
{
  "id": "01827ed4-c928-7a3c-9a30-7ab7cc169d11",
  "webhook_id": "01827ed4-c928-7a3c-9a30-7ab7cc169d11",
  "event_type": "AML_SCREENING",
  "timestamp": "2023-07-18T15:32:13Z",
  "payload": {}
}
```

***

## 2. Registering Webhook URLs

You can manage webhooks from your **Dashboard → API → Webhooks** tab.

There, you can:

* Add one or more webhook endpoints.
* Assign events (e.g. `AML_SCREENING` and etc.).
* Test and validate your configuration before going live.

Each webhook URL can be specific to an environment:

| Environment    | Base URL                          | Description                                  |
| -------------- | --------------------------------- | -------------------------------------------- |
| **Sandbox**    | `https://sandboxapi.dataspike.io` | For integration testing with simulated data. |
| **Production** | `https://api.dataspike.io`        | For live verification and AML events.        |

After saving, click **“Send Test”** to verify your endpoint works correctly — a dummy event will be sent immediately.

> 💡 You can register multiple webhooks for different services (e.g. one for AML alerts, one for verifications).

***

## 3. Verifying Webhook Signatures

Dataspike signs every webhook request with HMAC-SHA256 so you can verify it genuinely came from us and the payload has not been tampered with.

### Signature header

Each request includes:

| Header                | Description                                                  |
| --------------------- | ------------------------------------------------------------ |
| `X-Webhook-Signature` | Signature in the format `t={unix_timestamp},v1={hex_digest}` |

```
X-Webhook-Signature: t=1720018333,v1=a3f4b2c1d5e6...
```

* `t` — Unix timestamp (seconds, UTC) of when the request was signed
* `v1` — HMAC-SHA256 digest of the signed payload, hex-encoded

### How the signature is computed

**Signed payload:** `"{t}.{raw_request_body}"`\
Concatenate the timestamp string, a literal `.`, then the raw JSON body bytes exactly as received — do not re-serialize or pretty-print.

**Key:** hex-decode the secret after stripping the `whsec_` prefix.

### Your signing secret

When you create a webhook, the API response includes `hmac_signing_secret`:

```json theme={null}
{
  "id": "01927ed4-c928-7a3c-9a30-7ab7cc169d11",
  "hmac_signing_secret": "whsec_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1"
}
```

<Warning>The signing secret is shown **only once** at creation time. Store it immediately in a secrets manager or environment variable — it cannot be retrieved again.</Warning>

To replace the secret, call the rotate endpoint:

```
POST /api/v3/organization/webhooks/{webhook_id}/hmac/rotate
```

The response contains a new `hmac_signing_secret`. Update your application with the new value before discarding the old one to avoid dropping events.

### Verification examples

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

  // Use express.raw({ type: "application/json" }) to preserve the raw body bytes
  function verifySignature(secret, rawBody, header) {
    const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
    const key = Buffer.from(secret.replace(/^whsec_/, ""), "hex");
    const payload = Buffer.concat([Buffer.from(`${parts.t}.`), rawBody]);
    const expected = crypto.createHmac("sha256", key).update(payload).digest("hex");
    if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))) {
      throw new Error("Invalid signature");
    }
  }
  ```

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

  def verify_signature(secret: str, raw_body: bytes, header: str) -> None:
      parts = dict(p.split("=", 1) for p in header.split(","))
      key = bytes.fromhex(secret.removeprefix("whsec_"))
      payload = parts["t"].encode() + b"." + raw_body
      expected = hmac.new(key, payload, hashlib.sha256).hexdigest()
      if not hmac.compare_digest(expected, parts["v1"]):
          raise ValueError("Invalid signature")
  ```

  ```go Go theme={null}
  import (
      "crypto/hmac"
      "crypto/sha256"
      "encoding/hex"
      "errors"
      "strings"
  )

  func verifySignature(secret string, rawBody []byte, header string) error {
      parts := make(map[string]string)
      for _, p := range strings.Split(header, ",") {
          if kv := strings.SplitN(p, "=", 2); len(kv) == 2 {
              parts[kv[0]] = kv[1]
          }
      }
      key, err := hex.DecodeString(strings.TrimPrefix(secret, "whsec_"))
      if err != nil {
          return err
      }
      mac := hmac.New(sha256.New, key)
      mac.Write([]byte(parts["t"] + "."))
      mac.Write(rawBody)
      expected := hex.EncodeToString(mac.Sum(nil))
      if !hmac.Equal([]byte(expected), []byte(parts["v1"])) {
          return errors.New("invalid signature")
      }
      return nil
  }
  ```
</CodeGroup>

***

## 4. Handling Webhook Events

Your endpoint should:

* Accept **HTTP POST** requests with a `Content-Type: application/json` header.
* Parse the incoming payload.
* Validate the event type and handle it accordingly.
* Respond with HTTP `200 OK` to acknowledge receipt.

Example Node.js handler:

```javascript theme={null}
import express from "express";
const app = express();
app.use(express.json());

app.post("/dataspike/webhook", (req, res) => {
  const event = req.body;
  console.log("Received Dataspike event:", event.event);

  if (event.event === "DOCVER_EVENT") {
    // Handle verification result
  } else if (event.event === "AML_SCREENING") {
    // Handle AML hit
  }

  res.sendStatus(200);
});

app.listen(3000, () => console.log("Listening for webhooks on port 3000"));
```

***

## 5. Accessing Webhook History

Dataspike keeps a complete history of all webhook deliveries.

From the **Dashboard → API → Webhooks** section, you can:

* View **successful** and **failed** webhook attempts.
* Inspect **delivery payloads and response codes**.
* **Replay** failed deliveries manually.

This gives you full visibility and control over event delivery reliability.

***

## 6. Testing and Troubleshooting

Before going live:

1. Test your webhook endpoint in the **Sandbox** environment.
2. Use the **“Send Test”** button in the dashboard to ensure it works.
3. Check logs in your app for failed requests or response timeouts.
4. Confirm you return an HTTP `200` within a few seconds of receipt.

If events are not delivered:

* Verify your server accepts **HTTPS POST** requests.
* Ensure your endpoint is reachable from public networks.
* Review **Dashboard → API → Webhooks → History** for error details.

***

## Summary

Once configured, webhooks let you:

* Receive instant updates on verification, AML, and KYT events.
* Automate user state updates or trigger downstream processes.
* Monitor and replay webhook events from the dashboard.

***

## Next steps

* [**First Document Verification**](/document-verification/first-verification) — create applicants and run your first check.
* [**Web SDK Overview**](/web-sdk) — embed document verification into your product.
* [**AML Screening**](/aml-screening) — automate sanctions and watchlist checks.
