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

# Overview

> Cold email infrastructure from InboxKit; buy and connect domains and Google or Microsoft mailboxes, manage DNS, warmup and sequencer exports, and watch deliverability

Use **InboxKit** through Corsair: one client, typed API calls, local DB sync, and incoming webhooks.

Copy your team key from **Settings → API** in [InboxKit](https://app.inboxkit.com/settings/api). One key covers the whole team, including every mailbox's password, so store it as you would a password.

Things to know before you use it:

* **Real money.** 17 operations can charge the team's wallet or saved card, and their descriptions say so. They are `destructive`, so `cautious` mode asks first.
* **Nothing but a read is retried.** InboxKit has no idempotency keys, and a purchase that timed out may still have gone through. The error says so: check `domains.list` or `mailboxes.list` before repeating one. An error handler in your app that asks for a retry can't repeat it either: a retry of a call whose outcome is unclear gets the same error back with nothing sent. A new call goes through, so check first.
* **Unexpected answers.** If InboxKit's answer doesn't fit the documented shape, you get `{ parse_warning, raw }` with the answer in `raw`. The call still happened, so don't repeat it.
* **Workspaces.** Most operations act on one workspace. Pass `workspaceId` on the call or set `inboxkit({ workspaceId })`. With neither, a team with one workspace uses that one (found with one extra read per call), and a team with several gets an error naming them, even on a read.
* **Live sending infrastructure.** Changing a password or username, deleting or repairing DNS records, or running a resetup can stop a working mailbox. These are `destructive` too. Adding or editing a DNS record is `write`, as on our other DNS plugins, so check an MX change before you make it.
* **Fields left out on purpose.** `workspaces.create` takes no webhook URL, `mailboxes.update` no username and `sequencers.add` and `sequencers.update` no auto-export. InboxKit's API has them, but each can send mailbox data elsewhere or change a live address. Use `workspaces.updateWebhook` and `mailboxes.changeUsername`, which need approval in `cautious` mode, and the dashboard for auto-export.
* **Credentials.** `mailboxes.showCredentials` and `mailboxes.generateTotp` return plaintext to whoever calls them. Corsair doesn't log or store them, but your agent's transcript may.
* **Not covered:** InboxKit's unified inbox (reading and sending email, drafts, labels) and the team-level webhook URL. They are in InboxKit's MCP server and dashboard but not its documented REST API. The dashboard's **Real-time email events** switch isn't handled yet either, because nothing documents those deliveries. Leave it off: each one would get a 404, and InboxKit pauses a URL after five failures in a row.

**Limits:** 5,000 requests a minute in general; domain search and availability 50 a minute; bulk mailbox provisioning 10 a minute. Reads wait out a short limit and retry; anything else gets the error.

**What you get:**

* 181 typed API operations
* 3 synced entities (`domains`, `mailboxes`, `workspaces`) for fast `.search()` / `.list()`
* 4 incoming webhook event types

## Setup

**1. Install**

```bash npm theme={null}
npm install corsair @corsair-dev/inboxkit better-sqlite3
npm install --save-dev @types/better-sqlite3
```

```bash yarn theme={null}
yarn add corsair @corsair-dev/inboxkit better-sqlite3
yarn add --dev @types/better-sqlite3
```

```bash pnpm theme={null}
pnpm install corsair @corsair-dev/inboxkit better-sqlite3
pnpm install --save-dev @types/better-sqlite3
```

```bash bun theme={null}
bun add corsair @corsair-dev/inboxkit better-sqlite3
bun add --dev @types/better-sqlite3
```

**2. Add the plugin**

```ts corsair.ts theme={null}
import Database from 'better-sqlite3';
import { createCorsair } from 'corsair';
import { inboxkit } from '@corsair-dev/inboxkit';

export const corsair = createCorsair({
	plugins: [
		inboxkit(),
	],
	database: new Database('corsair.db'),
	kek: process.env.CORSAIR_KEK!,
	multiTenancy: true,
	hub: {
		projectApiKey: process.env.CORSAIR_API_KEY!,
		signingSecret: process.env.CORSAIR_SIGNING_SECRET!,
	},
});
```

With `multiTenancy: true`, scope calls with `corsair.withTenant(id)`. See [Quick start](https://docs.corsair.dev/quick-start.md) for KEK + Hub keys, and [Multi-tenancy](https://docs.corsair.dev/concepts/multi-tenancy.md) for account isolation.

**3. Choose authentication**

> [tab] API Key (Recommended)
>
> No setup required yet. When you make your first request as a tenant, Corsair prompts for the API key.
>
> ```ts theme={null}
> inboxkit()
> ```
>
> More: [API Key](https://docs.corsair.dev/concepts/api-key)

**4. Connect a tenant**

Mint a connect link and send the tenant to it. Hub hosts the page and delivers the result to your app — see [Connect / OAuth](https://docs.corsair.dev/management/connect).

```ts theme={null}
const { connectUrl } = await corsair.manage.connect.createLink({
	plugin: 'inboxkit',
	tenantId: 'acme',
});
// redirect the user's browser to connectUrl
```

## Example API calls

**List the workspace's domains**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.inboxkit.api.domains.list({
	limit: 20,
	status: ['active'],
});
```

**Add a DNS record**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.inboxkit.api.dns.add({
	domain: 'example.com',
	records: [{
		host: 'www',
		type: 'CNAME',
		value: 'example.net',
		ttl: 3600,
	}],
});
```

See the full list on the [API](https://docs.corsair.dev/plugins/inboxkit/api.md) page.

## Query synced data

Mailboxes and domains seen through list operations and webhooks are kept locally, without credentials.

```ts theme={null}
const tenant = corsair.withTenant('acme');
const rows = await tenant.inboxkit.db.mailboxes.search({
	data: { status: 'active' },
	limit: 10,
});
```

Synced entities: `domains`, `mailboxes`, `workspaces`. See [Database](https://docs.corsair.dev/plugins/inboxkit/database.md) for filters and operators.

## Webhooks

Set the URL under **Settings → API → Webhooks** in InboxKit, and turn off **Include mailbox credentials** there unless you need them. With it on, which is the default, InboxKit sends the mailbox's decrypted passwords in this delivery. The plugin removes them before the handler returns, so `after` hooks, local data and `result.body` never see them. A `before` hook runs first and does see them, so don't log the request there.

```ts theme={null}
inboxkit({
    webhookHooks: {
        mailboxes: {
            statusChanged: {
                after: async (ctx, result) => {
                    if (result.data?.data.mailbox.status === 'active') console.log('Ready:', result.data.data.mailbox.email);
                }
            },
        },
    },
})
```

Mount your framework handler once (see [Frameworks](https://docs.corsair.dev/frameworks/next.md)), then point the provider at that URL. Full event list: [Webhooks](https://docs.corsair.dev/plugins/inboxkit/webhooks.md). Concepts: [Webhooks](https://docs.corsair.dev/concepts/webhooks.md), [Hooks](https://docs.corsair.dev/concepts/hooks.md).

## What's next

> [card] [API reference](https://docs.corsair.dev/plugins/inboxkit/api.md)
>
> Every `inboxkit.api.*` operation with input and output types.

> [card] [Database](https://docs.corsair.dev/plugins/inboxkit/database.md)
>
> Synced entities, search filters, and operators.

> [card] [Webhooks](https://docs.corsair.dev/plugins/inboxkit/webhooks.md)
>
> Event paths, payloads, and `webhookHooks` examples.

> [card] [Connect / OAuth](https://docs.corsair.dev/management/connect)
>
> createLink, Hub delivery, and tenant connect flows.

> [card] [Use with agents](https://docs.corsair.dev/mcp-adapters/mcp-adapters)
>
> Expose this plugin's operations as MCP tools.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.