> ## 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

> Unipile API v2 in one plugin. Messaging on LinkedIn, WhatsApp, Instagram and Telegram, email on Gmail, Outlook and IMAP, Google and Outlook calendars, LinkedIn and Instagram posts, LinkedIn prospecting with Sales Navigator, and signed webhooks for every Unipile event.

Use **Unipile** through Corsair: one client, typed API calls, and incoming webhooks.

Every account-level call takes the `account_id` (acc\_…) of a connected account; connect one with `accounts.createAuthLink` (LinkedIn can sign in with credentials, cookies or the UniLogin extension). One plugin covers 148 operations: chats and messages on any messaging provider, emails, drafts and folders, calendars and events, posts and comments, LinkedIn searches, Sales Navigator lists, and admin (scopes, API keys, webhooks). On LinkedIn, chats are listed with `inboxes.listChats` and started with `inboxes.startChat` (inbox `CLASSIC_PRIMARY`); `chats.list` and `chats.start` cover WhatsApp, Telegram and Instagram.

Writes are never retried after a timeout or 5xx, so a lost answer cannot cause a duplicate message, email, invitation or post. LinkedIn calls that spend a daily budget (profile and company views, post reads, searches) are only retried after Unipile's own 429. Unipile does not pace sends for you: LinkedIn allows roughly 100-200 invitations a week and about 80-100 profile views a day. If Unipile accepts a write but answers with an unexpected body, the call returns `{ parse_warning, raw }` instead of throwing; check `result.parse_warning !== undefined` before reading fields, and do not resend. Pictures and attachments return their type and size unless `include_content` is set.

Scopes, API keys and webhook endpoints need a Unipile **Service API Key**; Account API Keys get `403 api/insufficient_permissions`. Deliveries are verified with the endpoint's signing secret (`unipile-signature` header, HMAC-SHA256 of the raw body), so pass the raw request body to Corsair and set `webhookSecret` (or store the webhook signature) to that secret. Secrets are returned once: `webhookEndpoints.create` and `apiKeys.create`; other calls never show them.

**What you get:**

* 148 typed API operations
* 40 incoming webhook event types

## Setup

**1. Install**

```bash npm theme={null}
npm install corsair @corsair-dev/unipile
```

```bash yarn theme={null}
yarn add corsair @corsair-dev/unipile
```

```bash pnpm theme={null}
pnpm install corsair @corsair-dev/unipile
```

```bash bun theme={null}
bun add corsair @corsair-dev/unipile
```

**2. Add the plugin**

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

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

Multi-tenancy is the default — 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**

**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}
unipile()
```

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: 'unipile',
	tenantId: 'acme',
});
// redirect the user's browser to connectUrl
```

## Example API calls

**Look up a LinkedIn profile**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.unipile.api.users.getProfile({ account_id: 'acc_9f2c1d7e', user_id: 'williamhgates' });
```

**Send a LinkedIn invitation**

```ts theme={null}
const tenant = corsair.withTenant('acme');
await tenant.unipile.api.relationRequests.create({ account_id: 'acc_9f2c1d7e', user_id: 'ACoAAB1cDeFgHiJkLmNoPqRsTuVwXyZ0123456', message: 'Hi Maya, I enjoyed your post on field data.' });
```

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

## Webhooks

Runs when an invitation is accepted. LinkedIn can report it up to 6 hours late.

```ts theme={null}
unipile({
    webhookHooks: {
        relations: {
            new: {
                after: async (ctx, result) => {
                    console.log('New connection', result.data?.payload.user.display_name);
                }
            },
        },
    },
})
```

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/unipile/webhooks.md). Concepts: [Webhooks](https://docs.corsair.dev/concepts/webhooks.md), [Hooks](https://docs.corsair.dev/concepts/hooks.md).

## What's next

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

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

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

> **[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.