# Corsair Example Usage: Complete Guide with Code Samples and Integration Patterns

> Explore Corsair example usage with code samples and integration patterns. Learn to create type-safe instances, register plugins, and call APIs seamlessly for efficient data persistence.

- Repository: [corsairdev/corsair](https://github.com/corsairdev/corsair)
- Tags: tutorial
- Published: 2026-09-01

---

**Corsair example usage starts with creating a type-safe instance via `createCorsair()`, registering plugins for services like Slack or Linear, then calling APIs through a tenant-scoped interface that automatically persists data to your database.**

Corsair is an open-source integration platform that unifies third-party service APIs behind a single, strongly-typed interface. According to the corsairdev/corsair source code, every integration follows the same pattern: initialize the core, register plugins, obtain a tenant-scoped instance, and call service-specific methods with full autocomplete and compile-time safety.

## Creating Your First Corsair Instance

The foundation of every Corsair integration is the `createCorsair()` function exported from the core package. This function accepts a configuration object with your database connection, encryption key, and plugin array.

In [`packages/corsair/README.md`](https://github.com/corsairdev/corsair/blob/main/packages/corsair/README.md), the minimal setup requires four properties:

- `database` — Your Prisma database instance for automatic persistence
- `kek` — A secret key used for encryption (environment variable recommended)
- `plugins` — Array of initialized plugin instances
- `multiTenancy` — Boolean enabling tenant-scoped access

```ts
import { createCorsair } from 'corsair';
import { slack } from '@corsair-dev/slack';
import { linear } from '@corsair-dev/linear';
import { resend } from '@corsair-dev/resend';
import { database } from './db';

export const corsair = createCorsair({
  database,
  multiTenancy: true,
  kek: process.env.CORSAIR_KEK!,
  plugins: [slack(), linear(), resend()],
});

```

This example appears in [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) and demonstrates the standard pattern for combining multiple services in one instance.

## Tenant-Scoped API Calls with Corsair

When **multi-tenancy** is enabled, all data access must go through a tenant-scoped instance. This ensures complete data isolation between customers or organizations.

### Obtaining a Tenant Instance

Call `withTenant()` on your Corsair instance and pass a unique tenant identifier:

```ts
const tenant = corsair.withTenant('tenant_123');

```

As implemented in [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) (line 16), this returns an object with the same plugin structure but scoped to the specified tenant.

### Calling Plugin APIs

Every plugin exposes identical access patterns: `tenant.{plugin}.api.{resource}.{action}`. TypeScript generates these types from each service's OpenAPI specification, providing full IntelliSense.

```ts
// Send a Slack message
const slackMessage = await tenant.slack.api.messages.post({
  channel: 'C01234567',
  text: 'Hello from Corsair! 🚀',
});

// Create a Linear issue
const linearIssue = await tenant.linear.api.issues.create({
  title: 'New feature request',
  teamId: 'TEAM_ABC',
  description: 'This is a great feature idea!',
});

```

Both snippets originate from [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) and showcase the unified syntax across different services.

## Database Persistence and Queries

Corsair automatically syncs every API response to your configured database. This creates a local, queryable cache with identical type safety to the remote API.

### Querying Cached Data

Access the database layer through `tenant.{plugin}.db.{resource}.{operation}`:

```ts
const issues = await tenant.linear.db.issues.list();
issues.forEach(issue => {
  console.log(issue.data.title);
});

```

This pattern from [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) (line 40) demonstrates how to work with persisted data without additional API calls. The `.data` property contains the full object graph as returned by the original API.

## Handling Webhooks in Corsair

Webhook processing uses framework-agnostic handler classes that validate signatures and route events. Each plugin provides its own handler with service-specific validation logic.

### Slack Webhook Handler Example

The `createWebhookHandler` function in [`demo/sdk/unified-sdk/webhooks/slack.ts`](https://github.com/corsairdev/corsair/blob/main/demo/sdk/unified-sdk/webhooks/slack.ts) demonstrates complete webhook handling:

```ts
import { createWebhookHandler } from './webhooks/slack';

const handler = createWebhookHandler({ signingSecret: process.env.SLACK_SECRET });

handler.on('message', async event => {
  console.log('New message from', event.user, ':', event.text);
});

// In an Express route:
app.post('/webhook/slack', async (req, res) => {
  const result = await handler.handleWebhook(req.headers, req.body);
  if (result.success && result.challenge) {
    res.send({ challenge: result.challenge });
  } else {
    res.sendStatus(result.success ? 200 : 400);
  }
});

```

Key features of this implementation:

- **Signature verification** using your Slack signing secret
- **Event routing** through the `.on()` method with typed event payloads
- **URL verification** handling for Slack's challenge-response protocol

### Gmail SDK Integration

The Gmail plugin follows the same initialization pattern with service-specific API methods. From [`demo/sdk/gmail/README.md`](https://github.com/corsairdev/corsair/blob/main/demo/sdk/gmail/README.md):

```ts
import { createCorsair, gmail } from 'corsair';
import { database } from './db';

const corsair = createCorsair({
  database,
  plugins: [gmail()],
  kek: process.env.CORSAIR_KEK!,
});

const tenant = corsair.withTenant('myTenant');

// List recent threads
const threads = await tenant.gmail.api.users.threads.list({
  userId: 'me',
});
console.log('Fetched', threads.length, 'threads');

```

## Additional Corsair Example Implementations

The repository maintains working demos for major integrations. Each demonstrates authentication flows, common API operations, and webhook configuration:

| Demo Location | Service | Key Features Demonstrated |
|-------------|---------|--------------------------|
| [`demo/sdk/gmail/README.md`](https://github.com/corsairdev/corsair/blob/main/demo/sdk/gmail/README.md) | Gmail | OAuth setup, thread listing, message retrieval |
| [`demo/sdk/github/README.md`](https://github.com/corsairdev/corsair/blob/main/demo/sdk/github/README.md) | GitHub | Repository events, pull request webhooks |
| [`demo/sdk/hubspot/README.md`](https://github.com/corsairdev/corsair/blob/main/demo/sdk/hubspot/README.md) | HubSpot | Contact management, property syncing |

These files confirm that **Corsair example usage** patterns remain consistent regardless of service complexity. The same `createCorsair → register plugins → withTenant → API call` workflow applies to every integration.

## Summary

- **Initialize once** with `createCorsair()` and your plugin array—recommend storing in [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) pattern
- **Scope by tenant** using `withTenant()` when `multiTenancy: true` for complete data isolation
- **Call APIs uniformly** through `tenant.{plugin}.api.{resource}.{action}` with full TypeScript support
- **Query local cache** via `tenant.{plugin}.db.{resource}` to avoid redundant API calls
- **Handle webhooks** with plugin-specific handlers that validate signatures and route events type-safely

## Frequently Asked Questions

### What database does Corsair require?

Corsair uses **Prisma** as its ORM layer. You pass your Prisma client instance to `createCorsair()`, and the platform handles all schema migrations and query generation automatically. The database stores both cached API responses and internal metadata for tenant isolation.

### Can I use Corsair without multi-tenancy?

Yes—set `multiTenancy: false` in your configuration. However, this is primarily intended for single-tenant applications or testing environments. The `withTenant()` method becomes unavailable, and you call APIs directly on the main instance instead.

### How does Corsair ensure type safety across different service APIs?

Type definitions are **generated from OpenAPI specifications** for each service. When you import a plugin like `@corsair-dev/slack`, you receive TypeScript types that match the current Slack API surface. This generation happens at build time, so your IDE provides accurate autocomplete without runtime overhead.

### Where are the best places to find working Corsair examples?

Start with [`demo/minimal/corsair.ts`](https://github.com/corsairdev/corsair/blob/main/demo/minimal/corsair.ts) for the simplest complete implementation. For service-specific patterns, consult the `/demo/sdk/` directory—each subdirectory contains a [`README.md`](https://github.com/corsairdev/corsair/blob/main/README.md) with authentication steps and common operations. The `demo/sdk/unified-sdk/webhooks/` folder provides production-ready webhook handlers with signature verification.