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

# KYB Webhooks

> Webhook events for KYB sessions and Business entities — triggers, payload schemas, and HMAC signature verification. Pay-per-call $2.00 KYB, no contracts.

Business Verification and Business entities emit webhook events on every meaningful state change. Subscribe to the events you care about via the [webhook destinations API](/management-api/webhook/list-destinations) or the Business Console.

## Event catalog

Webhook events are shared between User and Business sessions — the `session_kind` field on the payload tells you which kind the event refers to. Entity-level events are separate from session-level events.

### Session-level events

| Event            | When it fires                                                                                                                                                      |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `status.updated` | A session's status changed. For Business Verification (KYB) sessions the payload carries `session_kind: "business"`.                                               |
| `data.updated`   | A session's data was updated (registry refresh, key-people submission, document upload, AML rescan). Payload includes `session_kind: "business"` for KYB sessions. |

### Business entity events

| Event                     | When it fires                                                                                                    |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `business.status.updated` | The linked [Business entity](/entities/businesses/overview)'s status changed (`ACTIVE` / `FLAGGED` / `BLOCKED`). |
| `business.data.updated`   | The Business entity's profile fields or aggregate counters changed.                                              |

Subscribe to any combination on your webhook destination. See [entity webhooks](/entities/webhooks) for the full Business / User entity event reference.

## Envelope

Every webhook uses the same top-level envelope. The `session_kind` field inside `data` discriminates between User Verification (KYC) and Business Verification (KYB) for session-level events.

```json theme={null}
{
  "event": "status.updated",
  "event_id": "evt_01H8X...",
  "application_id": "app_abc123",
  "timestamp": "2026-04-18T12:30:00Z",
  "data": { ... }
}
```

## Payload shapes

### `status.updated` — Business Verification (KYB) session

Fires when a KYB session's status transitions.

```json theme={null}
{
  "event": "status.updated",
  "data": {
    "session_id": "bs_01H...",
    "session_kind": "business",
    "previous_status": "IN_PROGRESS",
    "status": "APPROVED",
    "vendor_data": "biz-acme-001",
    "workflow_id": "wf_kyb_standard",
    "features": ["KYB_REGISTRY", "KYB_COMPANY_AML", "KYB_DOCUMENTS", "KYB_KEY_PEOPLE"],
    "decision": { ...abbreviated KYB decision payload... },
    "changed_at": "2026-04-18T12:30:00Z"
  }
}
```

The `decision` block contains the same shape as [`GET /v3/session/{id}/decision/`](/sessions-api/retrieve-session) — `registry_checks[]`, `key_people_checks[]`, `document_verifications[]`, `aml_screenings[]`, etc.

### `data.updated` — Business Verification (KYB) session

Fires when session data (registry, key people, documents, AML) changed without a status transition.

```json theme={null}
{
  "event": "data.updated",
  "data": {
    "session_id": "bs_01H...",
    "session_kind": "business",
    "vendor_data": "biz-acme-001",
    "changed_fields": ["registry_checks", "key_people_checks"],
    "updated_at": "2026-04-18T14:00:00Z"
  }
}
```

Use `changed_fields` to efficiently decide what to re-fetch.

### `business.status.updated`

Fires when the [Business entity](/entities/businesses/overview) moves between `ACTIVE`, `FLAGGED`, or `BLOCKED`.

```json theme={null}
{
  "event": "business.status.updated",
  "data": {
    "vendor_data": "biz-acme-001",
    "uuid": "f7a9c1b2-4e6d-4f8a-9c5d-2a1b3c4d5e6f",
    "status": "FLAGGED",
    "previous_status": "ACTIVE",
    "reason": "manual",
    "actor": "compliance@yourcorp.com"
  }
}
```

### `business.data.updated`

Fires when the Business entity's profile fields or aggregate counters change.

```json theme={null}
{
  "event": "business.data.updated",
  "data": {
    "vendor_data": "biz-acme-001",
    "uuid": "...",
    "legal_name": "Acme Corporation Limited",
    "registration_number": "12345678",
    "country_code": "GBR",
    "session_count": 2,
    "approved_count": 1,
    "declined_count": 0,
    "in_review_count": 1,
    "changed_fields": ["session_count", "approved_count", "features"]
  }
}
```

## Signature verification

All webhooks are signed HMAC-SHA256 with your destination's shared secret, sent in the `X-Didit-Signature` header. Verify the raw request body before acting.

Example (Node.js):

```typescript theme={null}
import { createHmac, timingSafeEqual } from 'crypto';

function verifyWebhook(rawBody: string, signature: string, secret: string): boolean {
  const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
  const provided = Buffer.from(signature);
  const computed = Buffer.from(expected);
  return provided.length === computed.length && timingSafeEqual(provided, computed);
}
```

Full details in the [webhooks reference](/integration/webhooks).

## Retry policy

* Non-2xx responses trigger retries with exponential backoff.
* Up to 5 retries over \~24 hours.
* Each retry gets a new `X-Didit-Delivery` header but the same `event_id` — de-duplicate on your side.
* Repeated failures flip the destination to `disabled`.

## Subscribing

Subscribe to the events you care about on a [webhook destination](/management-api/webhook/create-destination):

```bash theme={null}
curl -X POST https://verification.didit.me/v3/webhook/destinations/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "KYB events",
    "url": "https://yourapp.com/webhooks/didit-kyb",
    "subscribed_events": [
      "status.updated",
      "data.updated",
      "business.status.updated",
      "business.data.updated",
      "activity.created"
    ]
  }'
```

Filter for business sessions on your side by checking `data.session_kind === "business"` inside `status.updated` and `data.updated` events.

## Next steps

<CardGroup cols={3}>
  <Card title="Webhooks reference" icon="bolt" href="/integration/webhooks">
    Destinations, signing, retries, common patterns.
  </Card>

  <Card title="Statuses" icon="list-check" href="/business-verification/statuses">
    Session and feature status reference.
  </Card>

  <Card title="Response schema" icon="file-lines" href="/business-verification/response-schema">
    Decoding the KYB decision payload.
  </Card>
</CardGroup>
