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

# Setup

> Wire the Corsair SDK into your app with Hub — install, add the /api/corsair route, add your keys, and start. Your app self-registers on first run.

Add Corsair Hub to a TypeScript app in five steps. Your app registers itself with Hub the first time it serves a request, so there is no delivery URL to type into the dashboard — the **App sync** indicator in the header turns green when it connects.

<Info>
  Prefer to hand this to a coding agent? Point it at this page: *"Set up Corsair Hub in this app. Follow [https://docs.corsair.dev/hub/setup.md](https://docs.corsair.dev/hub/setup.md) end to end."* It works through the same five steps below.
</Info>

## Prerequisites

A Hub project. Open your project's **Keys** tab in the [dashboard](/hub/dashboard) to copy its API key and signing secret. Secrets are shown once — never log or commit them.

## 1. Install Corsair and a plugin

```bash theme={null}
npm i corsair @corsair-dev/github
```

`@corsair-dev/github` is an example — swap it for the integration your app needs. Browse the [integrations catalog](https://api.corsair.dev/md/integrations) for plugin ids.

## 2. Create `corsair.ts` and link your database

```ts corsair.ts theme={null}
import "dotenv/config";

import { createCorsair } from "corsair";
import { github } from "@corsair-dev/github";

export const corsair = createCorsair({
    kek: process.env.CORSAIR_KEK!,
    database: db,
    hub: {
        projectApiKey: process.env.CORSAIR_DEV_API_KEY!,
        signingSecret: process.env.CORSAIR_DEV_SIGNING_SECRET!,
    },
    plugins: [github()],
});
```

Pass your app's database as `database`. Corsair persists connections and synced data there — Hub stores none of it (see [Hub overview](/hub/overview#hub-stores-none-of-your-credentials)).

## 3. Add the `/api/corsair` route

The handler serves Hub delivery — OAuth callbacks, connect pages, and self-registration — plus the management API, at its base path. Mount the adapter for your server:

<Tabs>
  <Tab title="Next.js">
    ```ts app/api/corsair/[[...path]]/route.ts theme={null}
    import { toNextJsHandler } from 'corsair';
    import { corsair } from '@/server/corsair';

    export const { GET, POST, OPTIONS } = toNextJsHandler(corsair, {
        basePath: '/api/corsair',
    });
    ```

    <Note>Pages Router? Export a catch-all API route at `pages/api/corsair/[...path].ts` and forward `req`/`res` through the same `toNextJsHandler`. The App Router is the supported default.</Note>
  </Tab>

  <Tab title="Express">
    ```ts server.ts theme={null}
    import express from 'express';
    import { toExpressHandler } from 'corsair';
    import { corsair } from './corsair';

    const app = express();

    // Required: Hub delivers results as JSON POSTs. The adapter reads the parsed
    // body, so express.json() must run before the Corsair route.
    app.use(express.json());
    app.use('/api/corsair', toExpressHandler(corsair, { basePath: '/api/corsair' }));

    app.listen(3000);
    ```

    <Warning>Mount `express.json()` **before** the Corsair route. Without it, `req.body` is undefined and Hub's delivery POSTs arrive empty — connects will look like they hang.</Warning>
  </Tab>

  <Tab title="Hono">
    ```ts index.ts theme={null}
    import { Hono } from 'hono';
    import { toHonoHandler } from 'corsair';
    import { corsair } from './corsair';

    const app = new Hono();

    // Wildcard: Corsair routes several paths under the base (delivery, connect,
    // tenants). Match them all with `/*`, and keep basePath in sync with the mount.
    app.all('/api/corsair/*', toHonoHandler(corsair, { basePath: '/api/corsair' }));

    export default app;
    ```
  </Tab>

  <Tab title="Web-standard">
    Every adapter wraps one primitive: `managementHandler(corsair)` returns `(request: Request) => Promise<Response>`. Any framework whose routes speak the Fetch API calls it directly — no adapter needed.

    <CodeGroup>
      ```ts SvelteKit theme={null}
      // src/routes/api/corsair/[...path]/+server.ts
      import { managementHandler } from 'corsair';
      import { corsair } from '$lib/server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const GET = ({ request }) => handler(request);
      export const POST = ({ request }) => handler(request);
      ```

      ```ts Remix theme={null}
      // app/routes/api.corsair.$.ts
      import { managementHandler } from 'corsair';
      import { corsair } from '~/server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const loader = ({ request }) => handler(request);
      export const action = ({ request }) => handler(request);
      ```

      ```ts Astro theme={null}
      // src/pages/api/corsair/[...path].ts
      import { managementHandler } from 'corsair';
      import { corsair } from '../../../server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const GET = ({ request }) => handler(request);
      export const POST = ({ request }) => handler(request);
      export const prerender = false;
      ```

      ```ts Nuxt theme={null}
      // server/routes/api/corsair/[...path].ts
      import { fromWebHandler } from 'h3';
      import { managementHandler } from 'corsair';
      import { corsair } from '~/server/corsair';

      // h3's fromWebHandler adapts the (Request) => Response handler to Nitro.
      export default fromWebHandler(
          managementHandler(corsair, { basePath: '/api/corsair' }),
      );
      ```

      ```ts Workers / Bun / Deno theme={null}
      import { managementHandler } from 'corsair';
      import { corsair } from './corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export default { fetch: (request: Request) => handler(request) };
      ```
    </CodeGroup>

    <Note>Backend not in JavaScript? Corsair's SDK is TypeScript-only. Integrate over the [Hub REST API](/hub/rest-api) instead.</Note>
  </Tab>
</Tabs>

You do not put the delivery URL in your `hub` config — it is resolved per environment (see [Delivery URLs](/hub/delivery-urls)).

## 4. Add your keys to `.env`

Copy the values from your project's **Keys** tab. Never commit them.

```bash .env theme={null}
CORSAIR_DEV_API_KEY=ck_dev_...
CORSAIR_DEV_SIGNING_SECRET=...
CORSAIR_KEK=...
```

The env var names are your choice — the dashboard uses `CORSAIR_DEV_*` for development and `CORSAIR_PROD_*` for production so both can coexist. Match whatever you reference in `corsair.ts`.

## 5. Start your app

```bash theme={null}
npm run dev
```

The first request to `/api/corsair` registers this app's delivery URL with Hub automatically. The **App sync** indicator in the dashboard header turns green — you are connected.

<Info>
  The delivery URL is derived from your app's own config (`CORSAIR_DELIVERY_URL` → `PORT`), never from an inbound request, and only development keys self-register. See [Delivery URLs](/hub/delivery-urls) for detection order and production setup.
</Info>

## What's next

<CardGroup cols={2}>
  <Card title="Delivery URLs" href="/hub/delivery-urls">
    How development and production delivery differ.
  </Card>

  <Card title="Environments" href="/hub/environments">
    Development vs production keys.
  </Card>

  <Card title="Connect / OAuth" href="/management/connect">
    Mint a connect link so users can sign in.
  </Card>

  <Card title="Dashboard" href="/hub/dashboard">
    Manage keys, connections, and delivery URLs.
  </Card>
</CardGroup>
