---
title: Webhooks Reference
path: reference/webhooks
status: published
---

# Webhooks Reference

Inbound webhook endpoints for receiving events from external services. For a deep dive into signature verification and event handling, see [Webhooks Deep Dive](../tutorials/webhook-integration.md).

**Base path:** `/api/v1/webhooks/`

## POST /api/v1/webhooks/scaikey

Receives identity lifecycle events from ScaiKey — partner, tenant, user, group, and application-assignment changes.

**Authentication:** HMAC signature. Caller sends:

- `X-ScaiKey-Signature: t=<timestamp>,v1=<hmac_sha256_hex>`
- `X-ScaiKey-Event-Id: <unique_event_id>` (optional; for idempotency)
- `X-ScaiKey-Event-Type: <event_type>` (optional; duplicated in body)

The signature is computed as `HMAC-SHA256(SCAIKEY_WEBHOOK_SECRET, "{timestamp}.{raw_body}")`. A 5-minute timestamp freshness check prevents replay.

**Request body:**

```json
{
  "event_id": "evt_abc123",
  "event_type": "user.created",
  "timestamp": "2026-04-23T10:42:00Z",
  "data": {
    "id": "usr_abc",
    "email": "user@example.com",
    "first_name": "First",
    "last_name": "Last",
    "status": "ACTIVE",
    "tenant": {
      "id": "tnt_xyz",
      "name": "BBinfra NL",
      "slug": "bbinfra-nl"
    }
  }
}
```

**Response:** `200 OK`

```json
{
  "success": true,
  "message": "Event user.created processed successfully",
  "event_id": "evt_abc123"
}
```

Processing errors return `200` with `success: false` to prevent retry loops — check logs for details.

## Supported event types

### Partner events

| Type | Trigger |
|------|---------|
| `partner.created` | New partner created in ScaiKey |
| `partner.updated` | Partner metadata changed |
| `partner.deleted` | Partner deleted (soft-delete in ScaiDNS) |

### Tenant events

| Type | Trigger |
|------|---------|
| `tenant.created` | New tenant created |
| `tenant.updated` | Tenant metadata changed (name, slug, settings) |
| `tenant.deleted` | Tenant deleted (suspended in ScaiDNS) |

### User events

| Type | Trigger |
|------|---------|
| `user.created` | User created and assigned to the ScaiDNS application |
| `user.updated` | User profile changed |
| `user.deleted` | User deleted or removed from the ScaiDNS application |

### Group events

| Type | Trigger |
|------|---------|
| `group.created` | Group created |
| `group.updated` | Group metadata changed |
| `group.deleted` | Group deleted (cascades to remove memberships) |
| `group.member_added` | User added to group |
| `group.member_removed` | User removed from group |

### Application events

| Type | Trigger |
|------|---------|
| `application.user_assigned` | User assigned to the ScaiDNS application (upserts user) |
| `application.user_unassigned` | User unassigned (soft-deletes user in ScaiDNS) |

## Event delivery

- **Scope.** ScaiKey sends events only for users and groups assigned to the ScaiDNS application, plus all tenants and partners.
- **Retry.** ScaiKey retries on `5xx` or non-`2xx` responses, with exponential backoff.
- **Order.** Not strictly guaranteed. Your handler must be idempotent.
- **Duplicates.** Possible on retries. Use `event_id` if you need strict deduplication — ScaiDNS currently does not dedupe on receipt.

## Configuring the webhook

Two sides need configuration:

**ScaiKey side:** Register the webhook URL (`https://your-scaidns.example.com/api/v1/webhooks/scaikey`) and signing secret in ScaiKey's admin UI.

**ScaiDNS side:** Set `SCAIKEY_WEBHOOK_SECRET` in `.env` to the same value. Restart the API server.

The secret is used by ScaiDNS to verify signatures. If it's unset, signature verification is skipped with a warning — intended for local development, never for production.

## Errors

| Status | Meaning |
|--------|---------|
| `200` with `success: false` | Event received but processing failed (no retry) |
| `400` | Invalid JSON body |
| `401` | Missing or invalid signature |

## Related

- [Webhooks Deep Dive](../tutorials/webhook-integration.md) — signature implementation, debugging.
- [Tenants and Users](../concepts/tenants-and-users.md) — how identities sync.
