# How to Configure Webhooks in Logto: Complete Management API Guide

> Configure Logto webhooks for real-time event notifications using the Management API. Learn to send event data reliably to your HTTP endpoints with this comprehensive guide.

- Repository: [Logto/logto](https://github.com/logto-io/logto)
- Tags: how-to-guide
- Published: 2026-07-05

---

**Logto delivers real-time event notifications to your HTTP endpoints through configurable webhooks managed via the Management API or Admin Console.**

Configuring webhooks in Logto enables your system to react instantly to authentication events like user creation, sign-in, and password resets. The webhook architecture spans from PostgreSQL storage to React-based administration interfaces, providing cryptographically signed payloads for secure verification. This guide explains the database schema, REST API endpoints, and security mechanisms implemented in the `logto-io/logto` repository.

## Webhook Architecture Overview

The Logto webhook system operates across five distinct layers, from persistent storage to the frontend interface.

### Database Schema

The `hooks` table defined in [`packages/schemas/tables/hooks.sql`](https://github.com/logto-io/logto/blob/main/packages/schemas/tables/hooks.sql) stores webhook metadata including the tenant ID, endpoint URL, subscribed events, enabled status, signing key, and custom headers. Each webhook record is scoped to a specific tenant and includes a unique `signingKey` generated by `generateStandardSecret()` during creation.

### Core Service Routes

The Management API implementation resides in [`packages/core/src/routes/hook.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/hook.ts). This file defines the CRUD endpoints, test functionality, and log retrieval routes. The route handlers validate incoming data using Zod schemas from [`packages/schemas/src/types/hook.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/hook.ts), specifically the `Hooks.createGuard` and `hookConfigGuard` validators.

### Middleware Integration

The `koaManagementApiHooks` middleware ([`packages/core/src/middleware/koa-management-api-hooks.js`](https://github.com/logto-io/logto/blob/main/packages/core/src/middleware/koa-management-api-hooks.js)) attaches the hook library to the Koa request context. This allows route handlers to access `libraries.hooks` for triggering deliveries through `triggerInteractionHooks` or `triggerTestHook`.

### Hook Library

The `createHookLibrary` function in [`packages/core/src/tenants/Libraries.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/tenants/Libraries.ts) provides the execution engine. It fetches enabled webhooks subscribed to specific events, constructs JSON payloads, calculates HMAC-SHA256 signatures, and dispatches HTTP POST requests to configured endpoints.

### Admin Console Frontend

The React-based UI consumes these APIs through components in [`packages/console/src/pages/TenantSettings/TenantMembers/hooks.ts`](https://github.com/logto-io/logto/blob/main/packages/console/src/pages/TenantSettings/TenantMembers/hooks.ts), while shared constants and event definitions live in [`packages/console/src/consts/webhooks.ts`](https://github.com/logto-io/logto/blob/main/packages/console/src/consts/webhooks.ts).

## Management API Endpoints

Logto exposes a comprehensive REST API for webhook lifecycle management. All endpoints require a valid Management API access token.

### Creating Webhooks

Send a `POST` request to `/api/hooks` to create a new webhook. The API automatically generates a cryptographically secure `signingKey` and returns it in the response.

```javascript
const createWebhook = async () => {
  const response = await fetch(
    `https://your-logto-domain/api/hooks`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer YOUR_ACCESS_TOKEN`,
      },
      body: JSON.stringify({
        name: 'My Slack Notifier',
        endpointUrl: 'https://hooks.slack.com/services/xxx/yyy/zzz',
        events: ['User.Created', 'User.SignedIn'],
        enabled: true,
        config: {
          headers: {
            'X-Custom-Header': 'my-value',
          },
        },
      }),
    }
  );

  if (!response.ok) throw new Error('Failed to create webhook');
  const hook = await response.json();
  console.log('Created webhook:', hook);
};

```

### Retrieving and Updating Webhooks

- **List webhooks**: `GET /api/hooks` supports pagination via `koaPagination` and optional execution statistics via the `includeExecutionStats=true` query parameter.
- **Get single webhook**: `GET /api/hooks/:id` retrieves a specific webhook configuration.
- **Update webhook**: `PATCH /api/hooks/:id` accepts partial updates to `name`, `endpointUrl`, `events`, or `enabled` status, validated against `Hooks.createGuard`.
- **Delete webhook**: `DELETE /api/hooks/:id` permanently removes the webhook configuration.

```javascript
const listWebhooks = async () => {
  const res = await fetch(
    `https://your-logto-domain/api/hooks?includeExecutionStats=true`,
    {
      headers: { Authorization: `Bearer YOUR_ACCESS_TOKEN` },
    }
  );
  const hooks = await res.json();
  console.table(hooks.map(h => ({
    id: h.id,
    name: h.name,
    events: h.events,
    enabled: h.enabled,
    last24hExecutions: h.executionStats?.last24hCalls ?? 0,
  })));
};

```

### Testing and Debugging

The `POST /api/hooks/:id/test` endpoint sends synthetic payloads to your endpoint without requiring a real event to occur. This utilizes the `triggerTestHook` function from the hook library.

```javascript
const testWebhook = async (hookId) => {
  const res = await fetch(
    `https://your-logto-domain/api/hooks/${hookId}/test`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer YOUR_ACCESS_TOKEN`,
      },
      body: JSON.stringify({
        events: ['User.Created'],
        config: {
          headers: { 'X-Test': 'true' },
        },
      }),
    }
  );

  if (res.status === 204) {
    console.log('Test payload sent successfully');
  } else {
    const error = await res.json();
    console.error('Test failed:', error);
  }
};

```

### Retrieving Execution Logs

Monitor webhook delivery through the `GET /api/hooks/:id/recent-logs` endpoint. It returns execution history from the last 24 hours by default, with optional filtering via `start_time`, `end_time`, and `logKey` parameters.

```javascript
const fetchRecentLogs = async (hookId) => {
  const url = new URL(`https://your-logto-domain/api/hooks/${hookId}/recent-logs`);
  url.searchParams.set('start_time', `${Date.now() - 24 * 60 * 60 * 1000}`);
  const res = await fetch(url, {
    headers: { Authorization: `Bearer YOUR_ACCESS_TOKEN` },
  });
  const logs = await res.json();
  console.log('Recent logs:', logs);
};

```

## Security and Signature Verification

Logto cryptographically signs every webhook request to prevent tampering and verify authenticity.

### Signature Header

Each POST request to your endpoint includes a `Logto-Signature` header containing an HMAC-SHA256 hash of the raw request body. The hash uses the webhook's unique `signingKey` stored in the `hooks` table.

### Key Rotation

Rotate compromised or expired signing keys using the `PATCH /api/hooks/:id/signing-key` endpoint. This generates a new key via `generateStandardSecret()` and returns it in the response body.

```javascript
const rotateKey = async (hookId) => {
  const res = await fetch(
    `https://your-logto-domain/api/hooks/${hookId}/signing-key`,
    {
      method: 'PATCH',
      headers: { Authorization: `Bearer YOUR_ACCESS_TOKEN` },
    }
  );
  const updatedHook = await res.json();
  console.log('New signing key:', updatedHook.signingKey);
};

```

## Webhook Delivery Lifecycle

Understanding the delivery mechanism helps debug failed requests and optimize endpoint performance.

1. **Event Trigger**: When a user signs in or registers, the interaction middleware ([`packages/core/src/routes/interaction/middleware/koa-interaction-hooks.ts`](https://github.com/logto-io/logto/blob/main/packages/core/src/routes/interaction/middleware/koa-interaction-hooks.ts)) detects the event type.
2. **Hook Resolution**: The system calls `libraries.hooks.triggerInteractionHooks`, which queries the database for enabled webhooks subscribed to that specific event.
3. **Payload Construction**: The library builds a JSON payload containing event data, tenant information, and timestamps.
4. **Signature Generation**: The system calculates the HMAC-SHA256 signature using the webhook's `signingKey` and attaches it as the `Logto-Signature` header.
5. **HTTP Dispatch**: The library executes an HTTP POST to the configured `endpointUrl`, including any custom headers defined in the webhook `config`.
6. **Log Persistence**: Execution results, including HTTP status codes and response times, are stored in the `logs` table for retrieval via the recent-logs API.

## Summary

- **Configure webhooks in Logto** through the Management API at `/api/hooks` or the Admin Console UI.
- The system stores webhook definitions in the `hooks` table and validates them using Zod schemas from [`packages/schemas/src/types/hook.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/hook.ts).
- **Security** relies on HMAC-SHA256 signatures in the `Logto-Signature` header, with keys managed via the signing-key rotation endpoint.
- **Testing** uses the `POST /hooks/:id/test` endpoint to send synthetic payloads without triggering real events.
- **Monitoring** is available through the recent-logs endpoint, which queries execution history stored in the `logs` table.

## Frequently Asked Questions

### What events can trigger Logto webhooks?

Logto supports events including `User.Created`, `User.Updated`, `User.Deleted`, `User.SignedIn`, `User.SignedOut`, and various organization and role-related events. The complete list is defined in the `hookEventGuard` schema within [`packages/schemas/src/types/hook.ts`](https://github.com/logto-io/logto/blob/main/packages/schemas/src/types/hook.ts).

### How do I verify webhook signatures in my endpoint?

Retrieve the `signingKey` from your webhook configuration, then compute an HMAC-SHA256 hash of the raw request body. Compare this value to the `Logto-Signature` header sent by Logto. If they match, the request originated from your Logto instance and was not tampered with during transit.

### Can I configure multiple webhooks for the same event?

Yes. Logto supports multiple webhook configurations per tenant, and all enabled webhooks subscribed to a specific event will receive the payload when that event occurs. Each webhook maintains its own `signingKey` and endpoint URL.

### What is the retry policy for failed webhook deliveries?

Logto implements an automatic retry mechanism for failed deliveries based on HTTP response status codes. Temporary failures (5xx status codes and network timeouts) trigger retry attempts, while permanent failures (4xx status codes) are logged but not retried. Check the recent-logs endpoint to view detailed delivery attempts and failure reasons.