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

# Webhooks

> Set up and manage webhook endpoints for real-time event delivery.

Webhooks push real-time event notifications to your server when verification, screening, and transaction events occur. This guide covers endpoint setup, signature verification, retry behavior, and IP allowlisting.

<Info>
  For a quick reference of all webhook events and payload structures, see [Webhooks Reference](/reference/webhooks).
</Info>

## Setting Up Endpoints

<Steps>
  <Step title="Create an Endpoint">
    Go to **Dashboard > Settings > Webhooks** and click **Add Endpoint**. Enter your HTTPS URL and select the events you want to receive.
  </Step>

  <Step title="Copy the Signing Secret">
    After creating the endpoint, copy the **Webhook Secret**. You will need this to verify incoming payloads. The secret is shown once and can be rotated at any time.
  </Step>

  <Step title="Subscribe to Events">
    Select which events are delivered to this endpoint. You can subscribe to all events or choose specific ones.
  </Step>

  <Step title="Activate the Endpoint">
    Toggle the endpoint to **Active**. Verilock will begin delivering events immediately.
  </Step>
</Steps>

## All Events

Verilock emits the following 13 webhook events:

| Event                  | Category     | Trigger                                    |
| ---------------------- | ------------ | ------------------------------------------ |
| `session.completed`    | KYC          | Verification session finished processing   |
| `session.approved`     | KYC          | Session approved -- identity verified      |
| `session.declined`     | KYC          | Session declined -- failed checks          |
| `session.expired`      | KYC          | Session expired before completion          |
| `aml.completed`        | AML          | AML screening finished processing          |
| `aml.match_found`      | AML          | Potential watchlist or PEP match detected  |
| `aml.monitoring.match` | Monitoring   | Continuous monitoring detected new matches |
| `transaction.flagged`  | Transactions | Transaction flagged for manual review      |
| `transaction.blocked`  | Transactions | Transaction automatically blocked          |
| `biometric.completed`  | Biometric    | Biometric authentication completed         |
| `database.validated`   | Database     | Database validation completed              |
| `face.duplicate_found` | Face Search  | Duplicate identity detected                |
| `wallet.screened`      | Wallet       | Wallet screening completed                 |

## Signature Verification

Every webhook includes an `X-Verilock-Signature` header containing an HMAC-SHA256 signature of the raw request body.

```bash theme={null}
# Compute the expected signature
echo -n '{"event":"session.approved","data":{...}}' | \
  openssl dgst -sha256 -hmac "whsec_your_signing_secret"
```

Verification steps:

1. Read the raw request body (do not parse JSON first)
2. Compute HMAC-SHA256 using your webhook secret
3. Compare the computed value to the `X-Verilock-Signature` header using a timing-safe comparison
4. Reject the request if they do not match

<Warning>
  Always use timing-safe comparison functions (`hash_equals` in PHP, `hmac.compare_digest` in Python, `crypto.timingSafeEqual` in Node.js) to prevent timing attacks.
</Warning>

## Payload Examples

<Tabs>
  <Tab title="session.approved">
    ```json theme={null}
    {
      "event": "session.approved",
      "data": {
        "session_id": "ses_a1b2c3d4e5f6",
        "status": "approved",
        "risk_score": 12,
        "decision": "approved",
        "applicant": {
          "first_name": "Jean",
          "last_name": "Dupont",
          "email": "jean@example.com"
        },
        "completed_at": "2026-03-15T14:30:00Z"
      },
      "timestamp": "2026-03-15T14:30:01Z",
      "webhook_id": "wh_evt_9f8e7d6c5b4a"
    }
    ```
  </Tab>

  <Tab title="aml.match_found">
    ```json theme={null}
    {
      "event": "aml.match_found",
      "data": {
        "screening_id": "aml_x7k9m2p4",
        "applicant_name": "Jean Dupont",
        "matches": [
          {
            "source": "sanctions_pep",
            "type": "PEP",
            "score": 92,
            "entity_name": "Jean-Pierre Dupont",
            "list": "France PEP Database"
          }
        ],
        "total_matches": 1
      },
      "timestamp": "2026-03-15T14:30:01Z",
      "webhook_id": "wh_evt_3a2b1c4d5e6f"
    }
    ```
  </Tab>

  <Tab title="transaction.blocked">
    ```json theme={null}
    {
      "event": "transaction.blocked",
      "data": {
        "transaction_id": "txn_m8n7o6p5q4",
        "amount": 15000.00,
        "currency": "USD",
        "risk_score": 94,
        "rules_triggered": ["structuring", "velocity_limit"],
        "decision": "blocked",
        "screened_at": "2026-03-15T14:30:00Z"
      },
      "timestamp": "2026-03-15T14:30:01Z",
      "webhook_id": "wh_evt_7g6h5i4j3k2l"
    }
    ```
  </Tab>

  <Tab title="wallet.screened">
    ```json theme={null}
    {
      "event": "wallet.screened",
      "data": {
        "session_id": "ses_a1b2c3d4e5f6",
        "wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
        "network": "ETH",
        "risk_score": 7.2,
        "risk_level": "high",
        "categories": ["mixer"],
        "decision": "review"
      },
      "timestamp": "2026-03-15T14:30:01Z",
      "webhook_id": "wh_evt_4c3b2a1d5e6f"
    }
    ```
  </Tab>
</Tabs>

## Retry Policy

Failed deliveries (non-2xx response or timeout after 10 seconds) are retried with exponential backoff:

| Attempt   | Delay      | Total Elapsed |
| --------- | ---------- | ------------- |
| 1st retry | 10 seconds | \~10s         |
| 2nd retry | 1 minute   | \~1m 10s      |
| 3rd retry | 5 minutes  | \~6m 10s      |
| 4th retry | 30 minutes | \~36m         |
| 5th retry | 2 hours    | \~2h 36m      |

After 5 failed attempts, the delivery is marked as failed. View and manually retry failed deliveries from **Dashboard > Webhooks > Delivery Log**.

<Tip>
  Return a `200` status code immediately and process the event asynchronously. Long-running webhook handlers increase the chance of timeouts and unnecessary retries.
</Tip>

## IP Allowlisting

If your infrastructure uses firewall rules, allowlist the following Verilock IP ranges:

```
203.0.113.0/24
198.51.100.0/24
```

<Note>
  IP ranges are subject to change. Subscribe to the [Verilock status page](https://status.verilock.io) for notifications about infrastructure changes.
</Note>

## Multiple Endpoints

You can configure up to 10 webhook endpoints per account. Each endpoint can subscribe to different events, allowing you to route events to different services:

| Endpoint                                    | Events                   | Use Case          |
| ------------------------------------------- | ------------------------ | ----------------- |
| `https://api.yourapp.com/webhooks/verilock` | `session.*`              | Application logic |
| `https://compliance.internal/webhooks`      | `aml.*`, `transaction.*` | Compliance team   |
| Zapier catch hook URL                       | `session.approved`       | Automation        |

## Delivery Log

The webhook delivery log in your dashboard shows:

* **Event type** and **payload**
* **Response status code** from your endpoint
* **Response time** in milliseconds
* **Retry count** and next retry time
* **Delivery status**: `delivered`, `retrying`, `failed`

Filter by event type, status, or date range to investigate delivery issues.

## Best Practices

<CardGroup cols={2}>
  <Card title="Respond Fast" icon="bolt">
    Return `200 OK` immediately. Queue the event for async processing to avoid timeouts.
  </Card>

  <Card title="Deduplicate" icon="fingerprint">
    Store processed `webhook_id` values. Skip events you have already handled to ensure idempotent processing.
  </Card>

  <Card title="Verify Signatures" icon="shield-check">
    Always validate `X-Verilock-Signature` before processing. Reject unsigned or incorrectly signed payloads.
  </Card>

  <Card title="Monitor Failures" icon="chart-line">
    Set up alerts for failed deliveries. Persistent failures may indicate endpoint issues or network problems.
  </Card>
</CardGroup>
