Skip to main content
Fastify is built for throughput, and the Corsair adapter keeps it that way. It prefers the original request bytes over Fastify’s parsed body, so you register a small raw-body parser once (shown below) and Hub’s signed deliveries verify cleanly. Mount it as a wildcard route, ideally inside its own plugin, so registration and encapsulation stay Fastify-idiomatic.

Install

The adapter ships in core corsair. Add a plugin package per service you integrate:

Create the instance

Build the instance once. The handler and your read/write code both import it.
corsair.ts
The handler and every .db / .api call on this page import this corsair. multiTenancy: true is what makes corsair.withTenant(id) available, and a tenant.github.* call resolves to the github() entry here. Add a service by installing its @corsair-dev/* package and dropping it into plugins. Database choices and the Hub keys are in Quick Start.

Mount the handler

Register the raw-body parser first, then mount the handler on both the wildcard and the bare base path. The parser is required: Fastify’s built-in JSON parser consumes the request bytes, and re-serializing them breaks Hub’s signature check, so deliveries fail with Invalid tunnel signature. Mounting only /api/corsair/* also leaves /api/corsair itself a 404.
corsair-plugin.ts
server.ts
./corsair is your createCorsair({ ... }) instance. See Getting Started if you haven’t built it yet.
The * wildcard is required: the base path alone (/api/corsair) won’t match /api/corsair/tenants or the Hub delivery sub-paths.

Resolve the tenant

Corsair only needs the tenant id, and your own auth produces it. Decorate the request with the authenticated user (in a hook or auth plugin), then read it off request.user.
getTenantId(request) is your own code that reads the signed-in user from your auth; it can return any stable id.

Read and write

Once a tenant is connected, reads never leave your database, which suits a hot handler that can’t afford a third-party round trip. Scope with withTenant(), then query the plugin’s entities.
routes/issues.ts
Entity fields live on .data in camelCase. Reads come from .db; creates, updates, and refreshes go through .api and land back in the same rows. See Dashboards for the full read/write pattern.

Connect a tenant

Fastify is a backend, so use the vanilla client from your frontend, a worker, or a script to check connection status and mint connect links against the route above.
1

Create the client

corsair-client.ts
createCorsairClient is a typed fetch wrapper over the management API, no React required. Use it from your frontend, a worker, or a script. Every route is typed against its response. Full surface on the Vanilla Client reference.
2

Read what's connected

connections.ts
connectionStatus.get returns a map of plugin id to connected | missing_credentials | not_connected, so you can show what’s live and what still needs connecting.
3

Mint a connect link

connect.ts
Hub hosts the consent screen and runs the OAuth handshake. When the user returns, the tokens are already encrypted in your own database. You never saw them, and neither did Hub. Swap "github" for any plugin you configured.

Go green

Start the server:
The first request to /api/corsair registers your delivery URL with Hub and turns the App sync dot in the dashboard header green.

Deploy

Deploy the Fastify server however you already run it. In production the same /api/corsair route becomes the delivery URL Hub calls, so ensure it’s publicly reachable. The first request re-registers the production URL.

Next

Vanilla client

Every management-API method the client exposes, fully typed.

Build a dashboard

The .db read / .api write pattern in full.

Connect / OAuth

The full connect flow, error codes, and retry.

Multi-tenancy

One flag and every user gets their own data and credentials.