# How to Integrate Karakeep with Other Services: A Complete tRPC and Webhooks Guide

> Learn how to integrate Karakeep with other services using its tRPC API and webhooks. Get real-time bookmark event notifications and query data effortlessly.

- Repository: [Karakeep App/karakeep](https://github.com/karakeep-app/karakeep)
- Tags: how-to-guide
- Published: 2026-07-07

---

**Karakeep exposes a fully-typed tRPC API and a webhooks system that allows external services to both query data and receive real-time notifications about bookmark events.**

Integrating with **karakeep-app/karakeep** enables you to build automated workflows, import legacy data, or sync bookmarks with third-party platforms. The repository provides two primary integration paths: a **tRPC API** for server-to-server calls and a **webhooks** infrastructure for event-driven architectures.

## Authenticate with the Karakeep tRPC API

All API interactions require authentication via bearer tokens. Karakeep manages these through the `apiKeys` router, which implements secure key generation and revocation.

### Generate API Keys

According to the source code in [`packages/trpc/routers/apiKeys.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/apiKeys.ts), you can programmatically create keys using the `apiKeys.create` mutation. This returns a secret key that must be attached to all subsequent requests.

```typescript
import { createTRPCClient, httpBatchLink } from '@trpc/client';

// Initialize client (replace with your Karakeep deployment URL)
const client = createTRPCClient({
  links: [httpBatchLink({ url: 'https://karakeep.example.com/trpc' })],
});

// Create API key (requires admin session or existing authentication)
const { key } = await client.apiKeys.create.mutate({
  name: 'my-integration-key',
});

```

The `apiKeys` router handles the cryptographic storage of secrets in the database, ensuring the raw key is never exposed after creation.

### Configure the tRPC Client with Authentication

For subsequent calls, attach the API key as a bearer token in the HTTP headers. The reference implementation in [`tools/seed-snapshot/src/index.ts`](https://github.com/karakeep-app/karakeep/blob/main/tools/seed-snapshot/src/index.ts) demonstrates this pattern:

```typescript
const client = createTRPCClient({
  links: [
    httpBatchLink({
      url: 'https://karakeep.example.com/trpc',
      fetch: (input, init) => {
        init!.headers = {
          ...init!.headers,
          Authorization: `Bearer ${process.env.KARAKEEP_API_KEY}`,
        };
        return fetch(input, init);
      },
    }),
  ],
});

```

## Call the Karakeep API to Manage Bookmarks

Once authenticated, you can invoke type-safe procedures to manipulate bookmarks, lists, and tags. The tRPC implementation provides IDE autocomplete for all available methods.

### Basic CRUD Operations

The following examples mirror the implementation in [`tools/seed-snapshot/src/index.ts`](https://github.com/karakeep-app/karakeep/blob/main/tools/seed-snapshot/src/index.ts):

```typescript
// Create a bookmark with metadata
const bookmark = await client.bookmarks.createBookmark.mutate({
  url: 'https://example.com/article',
  title: 'Interesting article',
  tags: ['tech', 'ai'],
});

// Query existing tags
const tags = await client.tags.list.query();

// Create a curated list
const list = await client.lists.create.mutate({
  name: 'Reading Queue',
});

```

The seed-snapshot tool demonstrates advanced patterns including waiting for background crawlers to complete metadata extraction using `await waitForCrawls(client, bookmarks)`.

## Set Up Webhooks for Real-Time Event Notifications

Karakeep's webhook system, implemented in [`packages/trpc/routers/webhooks.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/webhooks.ts), pushes event notifications to your infrastructure when data changes occur.

### Register a Webhook Endpoint

Create a webhook subscription by calling the `webhooks.create` mutation. The payload must specify the target URL and the event types you wish to monitor.

```typescript
await client.webhooks.create.mutate({
  url: 'https://myservice.example.com/karakeep/webhook',
  events: ['bookmark.created', 'bookmark.updated'],
});

```

The router implementation in [`packages/trpc/routers/webhooks.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/webhooks.ts) uses a `toPublicWebhook` helper (lines 16-22) to strip sensitive tokens from the response, exposing only a `hasToken` boolean flag. The actual token storage and validation logic resides in [`packages/trpc/models/webhooks.service.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/models/webhooks.service.ts).

### Handle Incoming Webhook Payloads

Your endpoint must accept HTTPS POST requests and respond with HTTP 200 within a few seconds. The JSON body follows the `zWebhookSchema` defined in [`packages/shared/types/webhooks.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/shared/types/webhooks.ts).

```typescript
import express from 'express';
const app = express();
app.use(express.json());

app.post('/karakeep/webhook', (req, res) => {
  const { event, data } = req.body;
  console.log(`Received ${event}:`, data);
  
  // Process event (e.g., sync to database, trigger notifications)
  
  res.sendStatus(200);
});

```

Failed deliveries are automatically retried by the background worker defined in [`apps/workers/workers/webhookWorker.ts`](https://github.com/karakeep-app/karakeep/blob/main/apps/workers/workers/webhookWorker.ts), which implements exponential backoff for resilient event delivery.

## Integration Examples

### Sync New Bookmarks to Slack

This Node.js example combines webhook reception with external API calls to forward bookmark notifications to a Slack channel:

```typescript
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import fetch from 'node-fetch';

const KARAKEEP_URL = 'https://karakeep.example.com/trpc';
const SLACK_WEBHOOK = 'https://hooks.slack.com/services/XXX/YYY/ZZZ';

const client = createTRPCClient({
  links: [
    httpBatchLink({
      url: KARAKEEP_URL,
      async fetch(input, init) {
        init!.headers = {
          ...init!.headers,
          Authorization: `Bearer ${process.env.KARAKEEP_API_KEY}`,
        };
        return fetch(input, init);
      },
    }),
  ],
});

// Register webhook endpoint (run once during setup)
await client.webhooks.create.mutate({
  url: 'https://my-server.example.com/karakeep/webhook',
  events: ['bookmark.created'],
});

// Express handler to forward events
import express from 'express';
const app = express();
app.use(express.json());

app.post('/karakeep/webhook', async (req, res) => {
  const { event, data } = req.body;
  if (event === 'bookmark.created') {
    await fetch(SLACK_WEBHOOK, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        text: `📚 New bookmark: ${data.title}\n${data.url}`,
      }),
    });
  }
  res.sendStatus(200);
});

app.listen(3000);

```

### Batch Import from CSV

Use the tRPC client to migrate existing bookmark archives into Karakeep:

```typescript
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import fs from 'fs';

const client = createTRPCClient({
  links: [httpBatchLink({ url: 'https://karakeep.example.com/trpc' })],
});

async function importCsv(filePath: string) {
  const rows = fs.readFileSync(filePath, 'utf8').split('\n');
  for (const row of rows) {
    const [url, title, tags] = row.split(',');
    await client.bookmarks.createBookmark.mutate({
      url,
      title,
      tags: tags?.split('|') ?? [],
    });
  }
}

await importCsv('./my-links.csv');

```

### Secure Webhook Verification

While Karakeep does not sign payloads, you can store a custom token during webhook creation and validate it on receipt:

```typescript
app.post('/karakeep/webhook', async (req, res) => {
  const { token, ...payload } = req.body;
  
  if (token && token !== process.env.KARAKEEP_WEBHOOK_TOKEN) {
    return res.sendStatus(403);
  }
  
  console.log('Validated payload:', payload);
  res.sendStatus(200);
});

```

## Summary

- **Authenticate** using the `apiKeys.create` mutation in [`packages/trpc/routers/apiKeys.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/apiKeys.ts) to generate bearer tokens for API access.
- **Query data** through the type-safe tRPC client by calling procedures like `bookmarks.createBookmark` or `tags.list`, as demonstrated in [`tools/seed-snapshot/src/index.ts`](https://github.com/karakeep-app/karakeep/blob/main/tools/seed-snapshot/src/index.ts).
- **Receive push notifications** by registering webhooks via `webhooks.create` in [`packages/trpc/routers/webhooks.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/webhooks.ts), with automatic retry logic handled by [`apps/workers/workers/webhookWorker.ts`](https://github.com/karakeep-app/karakeep/blob/main/apps/workers/workers/webhookWorker.ts).
- **Handle security** by storing verification tokens when creating webhooks (managed in [`packages/trpc/models/webhooks.service.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/models/webhooks.service.ts)) and validating them in your endpoint handlers.

## Frequently Asked Questions

### Does Karakeep provide a REST API or only tRPC?

Karakeep exposes a **tRPC API** rather than traditional REST endpoints. You interact with it using the `@trpc/client` library with an HTTP-batch link, which provides end-to-end type safety and autocomplete without requiring separate OpenAPI specifications.

### How do I authenticate API requests to Karakeep?

Generate an API key using the `apiKeys.create` mutation defined in [`packages/trpc/routers/apiKeys.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/apiKeys.ts), then attach it as a **Bearer token** in the `Authorization` header of every request. The key is generated once and must be stored securely by your application.

### What events can trigger Karakeep webhooks?

The webhook system supports events such as `bookmark.created`, `bookmark.updated`, and list modification events. When registering a webhook in [`packages/trpc/routers/webhooks.ts`](https://github.com/karakeep-app/karakeep/blob/main/packages/trpc/routers/webhooks.ts), you specify an array of event strings to filter which notifications you receive.

### How does Karakeep handle failed webhook deliveries?

The [`apps/workers/workers/webhookWorker.ts`](https://github.com/karakeep-app/karakeep/blob/main/apps/workers/workers/webhookWorker.ts) background service implements an exponential backoff retry mechanism. If your endpoint returns a non-200 status code or fails to respond, Karakeep automatically retries delivery multiple times before marking the webhook as failed.