# Custom Domain Kit integration instructions

Use this guide when a developer asks you to add Custom Domain Kit to their SaaS application. Inspect the repository first, match its framework and authentication conventions, and make the smallest secure integration that satisfies this guide.

## What Custom Domain Kit does

Custom Domain Kit provides customer custom-domain setup: DNS guidance, domain status checks, and signed status webhooks. The SaaS application remains responsible for its accounts, permissions, tenant data, and runtime hostname-to-tenant routing.

## Ask before editing

1. Ask the developer to create the application in the Custom Domain Kit dashboard. Its origin URL must be the stable HTTPS origin that receives customer-domain traffic.
2. Ask the developer to create a webhook endpoint for their public HTTPS webhook URL.
3. Ask for the application ID, Custom Domain Kit API base URL, application secret, and webhook signing secret. Put secrets only in the project's server-side secret configuration; do not print, commit, expose, or place them in browser code.
4. Identify the authenticated tenant or workspace ID, current actor ID, domain settings page, persistence model, and target page that must return tenant-specific content.

Never expose an application secret or webhook signing secret to browser code. Do not create an application or webhook endpoint through undocumented control-plane calls. Do not replace the product's authorization model: verify that the current user can manage the requested tenant before issuing a setup session.

## Implement the four required slices

### 1. Server setup session

Add a server-only endpoint at a framework-appropriate path such as `GET /api/custom-domain/setup-session`.

- Resolve `tenantId` and optional `actorId` from the authenticated server context, not untrusted browser input.
- Sign a fresh, short-lived setup token with the application secret. Use a 15-minute maximum lifetime and a unique nonce.
- Return `apiBaseUrl`, `appId`, `tenantId`, optional `actorId`, and `setupToken` with `Cache-Control: no-store`.
- Return authorization errors without revealing secrets or another tenant's information.

### 2. Customer domain settings page

On the tenant's domain settings page, register the Custom Domain Kit UI once and load the setup session from the new server endpoint. Render `<custom-domainkit-setup>` with only browser-safe values:

- `api-base-url`
- `app-id`
- `tenant-id`
- optional `actor-id`
- `setup-token`
- `setup-token-refresh-url`

Use the project's existing client-component or browser-bundle pattern. Keep the application secret and webhook signing secret out of HTML, client bundles, logs, and analytics.

### 3. Webhook receiver and domain mapping

Add a public server endpoint such as `POST /api/custom-domain/webhook`.

- Read the raw request body before parsing JSON.
- Verify `X-CustomDomainKit-Timestamp` and `X-CustomDomainKit-Signature` with the webhook signing secret.
- Accept `domain.status_changed` only after signature verification.
- De-duplicate by event ID, then persist `hostname`, `domainId`, `tenantId`, and status locally.
- Treat only active hostnames as routable. Return a successful response for a verified duplicate so delivery retries stop.

### 4. Target-page tenant resolution

At the project's target page or request-routing seam, resolve the request hostname in this order:

1. `X-CustomDomainKit-Original-Host`
2. `X-Forwarded-Host`
3. `Host`

Normalize the hostname by taking the first comma-separated value, removing a port, lowercasing, and rejecting empty or malformed values. Look up the active local hostname mapping, obtain its `tenantId`, then return the existing tenant-specific content. Unknown, inactive, or unauthorized hostnames must not fall through to another tenant's content.

## Verify before handing off

- Test that a user without tenant permission cannot get a setup session.
- Test that the setup-session response has no secret and is not cacheable.
- Test that the setup UI receives a refresh URL and no secret attributes.
- Test invalid and duplicate webhook deliveries, then confirm a valid active event stores the hostname-to-tenant mapping.
- Test Custom Domain Kit original-host precedence, forwarded-host fallback, host fallback, and an unknown hostname response.
- Run the repository's normal typecheck, tests, and build. Ask the developer to perform one real DNS, webhook, and custom-hostname traffic test before production rollout.
