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

# Working with webhooks

# Working with Webhooks

This guide explains how to register webhooks, handle incoming webhook events, and understand the custom headers and payloads provided by the Diligent AI API.

## 1. Registering and managing webhooks

You can register **multiple webhooks** (up to 10), each with its own URL, secret, and event filter — for example a production endpoint, a staging endpoint, and a data-warehouse ingester. When an event occurs, Diligent delivers it to **every active webhook whose filter includes that event type**.

Webhooks are managed with a standard CRUD API:

| Method & path                   | Purpose                                   |
| ------------------------------- | ----------------------------------------- |
| `POST /webhooks`                | Create a webhook                          |
| `GET /webhooks`                 | List all your webhooks                    |
| `GET /webhooks/{webhook_id}`    | Get a single webhook                      |
| `PATCH /webhooks/{webhook_id}`  | Update a webhook                          |
| `DELETE /webhooks/{webhook_id}` | Delete a webhook (delivery stops at once) |

<Note>
  `POST /webhooks` always **creates a new** webhook. To change an existing one, use `PATCH /webhooks/{webhook_id}` — re-posting will not update it.
</Note>

**Create a webhook** — subscribe an endpoint to a subset of events:

```json theme={null}
// POST /webhooks
{
  "webhook_url": "https://your-server.com/webhooks",
  "is_active": true,
  "secret": "your-secret",
  "events": ["cdd_state_changed", "alert_remediated"]
}
```

The response includes the new webhook's `id` and a `has_secret` flag (the secret itself is never returned):

```json theme={null}
{
  "id": "df89eb16-4c6a-439f-b668-7cca0cd786fa",
  "webhook_url": "https://your-server.com/webhooks",
  "is_active": true,
  "has_secret": true,
  "status": "active",
  "last_delivery_at": null,
  "last_delivery_status": null,
  "events": ["cdd_state_changed", "alert_remediated"]
}
```

**Update a webhook** — change only the fields you send. Omit `secret` to keep it, send `""` to remove it, or send a new value to replace it:

```json theme={null}
// PATCH /webhooks/df89eb16-4c6a-439f-b668-7cca0cd786fa
{
  "events": ["cdd_state_changed", "alert_remediated", "search_completed"],
  "is_active": false
}
```

**Delete a webhook** — `DELETE /webhooks/{webhook_id}` returns `204` and delivery to that endpoint stops immediately.

**Per-webhook event filtering:** each webhook only receives the event types listed in its `events` array, so different endpoints can subscribe to different events. The supported types are:

* `cdd_state_changed`: Triggered when the state of a CDD changes to inconclusive or complete.
* `monitoring_alert_fired`: Triggered when a monitoring alert is fired on failure.
* `cdd_document_fetched`: Triggered when a new document is successfully added to a CDD case.
* `search_completed`: Triggered when a name screening search completes and results are available.
* `alert_remediated`: Triggered when a name screening alert has been remediated (all hits resolved).
* `flow_run_completed`: Triggered when a flow run finishes successfully (`COMPLETED`).
* `flow_run_failed`: Triggered when a flow run fails (`FAILED`).

See the [Register Webhook API Reference](../../api-reference/webhooks/register) for full details.

## 2. Receiving Webhooks

When an event occurs, Diligent AI sends an HTTPS POST request to your registered endpoint.

### Custom Headers

Each webhook request includes custom headers to help you identify and verify the event:

| Header        | Description                                                                                                                                                                          |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Content-Type  | Always `application/json`                                                                                                                                                            |
| User-Agent    | Sender identifier (e.g., `DiligentAI/1.0`)                                                                                                                                           |
| X-Webhook-Id  | Unique ID of your webhook                                                                                                                                                            |
| X-Event-Id    | Unique ID of this delivery event                                                                                                                                                     |
| X-Customer-Id | Your customer ID                                                                                                                                                                     |
| X-Target-type | Entity type (`CDD`, `MONITORING_ALERT`, `NAME_SCREENING_SEARCH`, `NAME_SCREENING_ALERT`, or `FLOW_RUN`)                                                                              |
| X-Event-Name  | Name of the triggered event (`CDD_STATE_CHANGED`, `MONITORING_ALERT_FIRED`, `SEARCH_COMPLETED`, `CDD_DOCUMENT_FETCHED`, `ALERT_REMEDIATED`, `FLOW_RUN_COMPLETED`, `FLOW_RUN_FAILED`) |
| X-Signature   | HMAC signature for authenticity                                                                                                                                                      |

### Example Payloads

#### cdd\_state\_changed

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "CDD",
    "X-Event-Name": "CDD_COMPLETED",
    "X-Signature": "sha256=..."
  },
  "payload": "<CDD object as JSON string>"
}
```

* `payload`: Full CDD object (see [CDD Object](../../api-reference/cdd/get-cdd)).

#### monitoring\_alert\_fired

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "MONITORING_ALERT",
    "X-Event-Name": "MONITORING_ALERT_FIRED",
    "X-Signature": "sha256=..."
  },
  "payload": {
    "alert_id": "...",
    "monitoring_id": "...",
    "type": "FRAUD",
    "details": {
      "reason": "Suspicious activity detected",
      "triggered_at": "2025-07-31T05:12:03.123Z"
    }
  }
}
```

* `payload`: Alert object with details about the triggered alert.

#### cdd\_document\_fetched

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "CDD",
    "X-Event-Name": "CDD_DOCUMENT_FETCHED",
    "X-Signature": "sha256=..."
  },
  "payload": "<Full CDD object as JSON string>"
}
```

* `payload`: Full CDD object snapshot including all documents (see [CDD Object](../../api-reference/cdd/get-cdd)).

#### search\_completed

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "NAME_SCREENING_SEARCH",
    "X-Event-Name": "SEARCH_COMPLETED",
    "X-Signature": "sha256=..."
  },
  "payload": {
    "id": "search-id-123",
    "reference": "CUST-2024-001",
    "status": "COMPLETED",
    "input": [
      {
        "value": "John Doe",
        "label": "FULL_NAME"
      },
      {
        "value": "INDIVIDUAL",
        "label": "ENTITY_TYPE"
      }
    ],
    "hit_counts": {
      "FALSE_POSITIVE": 2,
      "TRUE_POSITIVE": 1,
      "UNRESOLVED": 3
    },
    "hits": [
      {
        "id": "hit-001",
        "provider_reference": "27318408899",
        "status": "UNRESOLVED",
        "fields": [
          {
            "value": "WX0014675452",
            "label": "Profile ID"
          },
          {
            "value": "John Doe",
            "label": "Name"
          }
        ],
        "hit_categories": ["SANCTION"],
        "remediation": {
          "sync_status": "PENDING",
          "determination": "UNRESOLVED",
          "action": "DO_NOTHING",
          "determined_at": "2024-01-15T10:30:00Z",
          "author": "DILIGENT",
          "summary": "Names match with high confidence"
        }
      }
    ],
    "created_at": "2024-10-02T12:00:00Z",
    "updated_at": "2024-10-02T14:30:00Z"
  }
}
```

* `payload`: Full search object with hits and remediation details.

#### alert\_remediated

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "NAME_SCREENING_ALERT",
    "X-Event-Name": "ALERT_REMEDIATED",
    "X-Signature": "sha256=..."
  },
  "payload": {
    "id": "714808a0-faf0-4e0f-a3a3-fbe490a10efd",
    "reference": "5jb7h9b1kiu51kbwyrjhog350",
    "alt_reference": "ABIGASQLIM3WR",
    "status": "COMPLETED",
    "remediation_status": "REMEDIATED",
    "profile_facts": [
      {
        "predicate": "has_name",
        "value": "Ryan Bailey",
        "citations": [{ "name": "PROFILE", "url": null }]
      },
      {
        "predicate": "date_of_birth",
        "value": "1992-01-27",
        "citations": [{ "name": "PROFILE", "url": null }]
      }
    ],
    "hits": [
      {
        "reference": "5jb766qtsj0e1kbwyrlh03gpe",
        "hit_categories": ["MEDIA"],
        "evidences": [
          {
            "type": "PRIMARY_NAME",
            "categories": ["NAME_GIVEN_NAME_EXACT_MATCH", "NAME_FAMILY_NAME_VARIANT_MATCH", "NAME_MAIN"],
            "supporting_facts": [
              {
                "predicate": "has_name",
                "value": "Ryan DAILEY",
                "citations": [{ "name": "HIT", "url": null }]
              },
              {
                "predicate": "has_name",
                "value": "Ryan Bailey",
                "citations": [{ "name": "PROFILE", "url": null }]
              }
            ]
          },
          {
            "type": "DOB",
            "categories": ["DOB_AMBIGUOUS", "DOB_YEAR_MISMATCH"],
            "supporting_facts": [
              {
                "predicate": "date_of_birth",
                "value": "1974",
                "citations": [{ "name": "HIT", "url": null }]
              },
              {
                "predicate": "date_of_birth",
                "value": "1975",
                "citations": [{ "name": "ARTICLE", "url": "https://example.com/article" }]
              },
              {
                "predicate": "date_of_birth",
                "value": "1992-01-27",
                "citations": [{ "name": "PROFILE", "url": null }]
              }
            ]
          }
        ],
        "resolution": {
          "status": "NOTHING",
          "summary": "DOB mismatch — all hit dates are 2+ years off the profile DOB",
          "author": "DILIGENT",
          "action": "COMMENT_FALSE_POSITIVE",
          "determination": "FALSE_POSITIVE",
          "applied_rule": {
            "name": "Date of Birth Mismatch"
          }
        }
      }
    ],
    "created_at": "2024-01-15T09:00:00Z",
    "updated_at": "2024-01-15T10:30:00Z"
  }
}
```

* `payload`: Full alert object. See [Get Alert](../../api-reference/name-screening/get-alert) for the complete schema reference.
* Each hit contains `evidences` with `supporting_facts` — the specific facts that drove the resolution decision, each with `predicate`, `value`, and a `citations` array indicating the data source (`HIT`, `PROFILE`, `ARTICLE`, `REGISTRY`, or `WEB_SEARCH`).

#### flow\_run\_completed

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "FLOW_RUN",
    "X-Event-Name": "FLOW_RUN_COMPLETED",
    "X-Signature": "sha256=..."
  },
  "payload": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "flow_id": "flow-abc123",
    "flow_version_id": "ver-def456",
    "triggered_at": "2025-07-31T10:00:00.000Z",
    "status": "COMPLETED",
    "started_at": "2025-07-31T10:00:01.000Z",
    "completed_at": "2025-07-31T10:00:45.000Z",
    "input": {
      "subject": "Acme Corp"
    },
    "report": "s3://flows-artifacts/reports/run-a1b2c3d4.json",
    "error": null,
    "meta": {
      "case_ref": "CASE-001"
    },
    "created_at": "2025-07-31T10:00:00.000Z",
    "updated_at": "2025-07-31T10:00:45.000Z"
  }
}
```

* `payload`: Full flow run object — the same shape returned by `GET /v1/flow-runs/{runId}`.
* Delivered only when the run status transitions to `COMPLETED` (not on intermediate states such as `QUEUED` or `RUNNING`).

#### flow\_run\_failed

```json theme={null}
{
  "headers": {
    "Content-Type": "application/json",
    "User-Agent": "DiligentAI/1.0",
    "X-Webhook-Id": "...",
    "X-Event-Id": "...",
    "X-Customer-Id": "...",
    "X-Target-type": "FLOW_RUN",
    "X-Event-Name": "FLOW_RUN_FAILED",
    "X-Signature": "sha256=..."
  },
  "payload": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "flow_id": "flow-abc123",
    "flow_version_id": "ver-def456",
    "triggered_at": "2025-07-31T10:00:00.000Z",
    "status": "FAILED",
    "started_at": "2025-07-31T10:00:01.000Z",
    "completed_at": "2025-07-31T10:00:12.000Z",
    "input": {
      "subject": "Acme Corp"
    },
    "report": null,
    "error": {
      "code": "EXECUTION_ERROR",
      "message": "entityName is required",
      "step": null
    },
    "created_at": "2025-07-31T10:00:00.000Z",
    "updated_at": "2025-07-31T10:00:12.000Z"
  }
}
```

* `payload`: Full flow run object — the same shape returned by `GET /v1/flow-runs/{runId}`.
* Delivered only when the run status transitions to `FAILED`.
* `CANCELLED` runs do not trigger either flow run webhook event.

## 3. Webhook Flow Diagram

Below is a simple flow of how a webhook is triggered and received:

```mermaid theme={null}
sequenceDiagram
  participant Diligent AI
  participant YourServer
  Diligent AI->>Diligent AI: Event occurs (e.g. CDD completed)
  Diligent AI->>YourServer: POST webhook with headers and payload
  YourServer->>Diligent AI: Responds with status code (200 OK if received)
```

* Diligent AI triggers the webhook when an event occurs.
* Your server receives a POST request with custom headers and event payload.
* Your server should process the event and return a 200 OK status to acknowledge receipt.

For best practices on securing your endpoint and verifying signatures, see [Securing Webhooks](securing-webhooks).
