---
title: Server API
description: Mount provider connection routes in Effect-native or async hosts while retaining application ownership of identity, persistence, and policy.
sidebar:
  label: Server
---

`domainkit/server` supplies one provider-connection HTTP seam for Effect-native and async hosts.
Identity, tenancy, credentials, short-lived continuations, durable authorization storage, and audit
policy remain host-owned.

## Async hosts

Use `createDomainKit` in a conventional async application. It accepts Promise-based host
capabilities and returns a standard Web handler:

```ts
import { createDomainKit } from "domainkit/server";

export const domainKit = await createDomainKit({
  baseURL: "https://app.example.com",
  basePath: "/api/domainkit",
  defaultReturnTo: "/domains",
  identity: hostIdentity,
  connectionPolicy: hostConnectionPolicy,
  providers: [cloudflare],
  pendingAuthorizations: redisPendingAuthorizations,
  persistence: managedDnsConnections,
});
```

The host supplies `persistence`; DomainKit does not choose a database, run migrations, or dispose
the host's database client. The optional `@domainkit/capsuledb` package remains an Effect-native
implementation rather than an implicit dependency of this factory.

## Effect-native hosts

Use `Server.make` in an existing Effect program or provide it as a Layer with `Server.layer`:

```ts
import { Server } from "domainkit/server";
import { Layer } from "effect";

const dependencies = Layer.mergeAll(
  IdentityLive,
  ConnectionPolicyLive,
  ProvidersLive,
  PendingAuthorizationsLive,
  ManagedDnsConnectionsLive,
  CryptoLive,
);

const DomainKitServerLive = Server.layer({
  baseURL: "https://app.example.com",
  basePath: "/api/domainkit",
  defaultReturnTo: "/domains",
}).pipe(Layer.provide(dependencies));

export const domainKit = Server.toWebHandler(DomainKitServerLive);
```

Both paths use the same route program. `Server.make` leaves Effect requirements visible;
`createDomainKit` adapts Promise capabilities at the foreign-runtime boundary.

## Mount the handler

The returned `fetch(Request)` works directly with Web-standard server frameworks.

```ts title="Hono"
app.all("/api/domainkit/*", (context) => domainKit.fetch(context.req.raw));
```

```ts title="Next.js App Router"
// app/api/domainkit/[...path]/route.ts
export const GET = domainKit.fetch;
export const POST = domainKit.fetch;
```

```ts title="TanStack Start"
// routes/api/domainkit/$.ts
export const Route = createFileRoute("/api/domainkit/$")({
  server: {
    handlers: {
      GET: ({ request }) => domainKit.fetch(request),
      POST: ({ request }) => domainKit.fetch(request),
    },
  },
});
```

Dispose the DomainKit handler during a long-lived host's shutdown. This releases only the runtime
created by DomainKit; the host still owns its persistence lifecycle. The default base path is
`/api/domainkit`. When `baseURL` is omitted, the start request's origin constructs the callback URL;
configure it explicitly behind a reverse proxy or custom domain.

## Routes

| Method | Path                                  | Behavior                                                          |
| ------ | ------------------------------------- | ----------------------------------------------------------------- |
| `POST` | `/api/domainkit/connection/start`     | Authenticates the host principal and returns an authorization URL |
| `GET`  | `/api/domainkit/callback/:providerId` | Consumes state once, commits the connection, and redirects        |

The start body accepts `providerId`, `method`, an optional provider-selection `domain`, an optional
existing `authorizationId`, and a same-origin `returnTo`. When `authorizationId` is present,
`Server.ConnectionPolicy` must authorize that exact aggregate for the authenticated principal
before DomainKit can reuse it. Callback redirects append
`domainkit=connected` and the public `connectionId` so the host UI can continue its setup flow.

## Host services

{/* reference-inventory:start */}

| Export   | Purpose                                                                       |
| -------- | ----------------------------------------------------------------------------- |
| `Server` | Routes, configuration, host service tags, errors, and the Web handler adapter |

{/* reference-inventory:end */}

| Service                         | Host responsibility                                                                 |
| ------------------------------- | ----------------------------------------------------------------------------------- |
| `Server.Identity`               | Authenticate a start request and return tenant-owned principal identifiers          |
| `Server.ConnectionPolicy`       | Authorize an exact existing aggregate before connection reuse                       |
| `Server.Providers`              | Build a configured interactive provider flow for the selected domain and callback   |
| `Server.PendingAuthorizations`  | Persist the opaque continuation and safe callback context until one-time consume    |
| `ManagedDnsConnections.Service` | Persist the durable authorization, credential, connection, and attachment aggregate |
| `Crypto.Crypto`                 | Generate continuation, authorization, and connection identifiers                    |

`createDomainKit` is also a named export for Promise hosts. Its `identity`, `connectionPolicy`,
`providers`, `pendingAuthorizations`, and `persistence` options correspond to these Effect
services. Build Effect sibling implementations with `Layer.mergeAll`, then provide the completed
dependency graph to `Server.layer` once.

## Failure behavior

Failures are returned as JSON with `category`, `message`, `operation`, and `retry`. Start requests
without a host identity return `401`, and denied aggregate reuse returns `403`. Invalid provider
input, unsafe return URLs, mismatched callbacks, expired state, and replayed state return `400`.
Configuration failures return `500`, provider infrastructure failures return `502`, and storage
failures return `503`. Provider tokens and opaque continuation payloads are never serialized to the
browser response.
