---
title: Integrate a host application
description: Place identity, authorization storage, provider credentials, plan attempts, receipts, authenticated endpoints, and React transport around DomainKit.
seo:
  title: Integrate DomainKit into a SaaS application
---

This guide describes the complete application boundary around DomainKit. The host application owns
the security and durability model; DomainKit owns portable connection, planning, authorization,
provider, verification, and cleanup semantics.

## Architecture

```text
browser or product client
  -> authenticated host endpoints
  -> host identity, tenant policy, and consent checks
  -> durable connection + plan-attempt + receipt storage
  -> domainkit
  -> Cloudflare, Vercel, or another DnsProvider
```

`@domainkit/react` uses the same boundary through `Transport.Service`:

```text
@domainkit/react
  -> Transport.Service
  -> authenticated host client
  -> the server lifecycle above
```

Provider credentials never cross into the browser transport.

## Decide what is durable

| State                             | Lifetime                 | Host responsibility                                                               |
| --------------------------------- | ------------------------ | --------------------------------------------------------------------------------- |
| OAuth or integration continuation | Short-lived and one-time | Store until callback consumption; loss may require restarting consent             |
| Provider authorization            | Durable                  | Persist account context, capabilities, credential reference, and revocation state |
| Encrypted credential              | Durable and secret       | Encrypt at rest, restrict access, rotate, and audit use                           |
| Owner binding and domain grant    | Durable                  | Bind provider authority to your tenant and permitted domains                      |
| Plan attempt and authorization    | Durable through apply    | Correlate a server-owned plan with the digest the user reviewed                   |
| Apply receipt                     | Durable                  | Preserve confirmed writes and partial outcomes for later cleanup                  |
| Public-DNS observation            | Evidence, not authority  | Persist only if your product needs history, polling, or readiness state           |

Do not use a browser store or evictable cache as authoritative storage for provider authorizations,
plans, or receipts.

## 1. Define product requirements on the server

Your product decides which DNS records it needs and why. Decode those requirements at a trusted
boundary:

```ts
import { DnsRecord } from "domainkit";

const requirement = DnsRecord.parse({
  _tag: "TXT",
  metadata: {
    ownership: "product",
    provenance: "domain-onboarding",
    purpose: "domain-verification",
  },
  name: "_verify.example.com",
  policy: "append",
  ttl: 300,
  value: "verification-value",
});
```

The browser may display a transport projection of these records, but it must not choose ownership,
conflict policy, or provider authority.

## 2. Implement authorization storage

Supply one `AuthorizationLifecycle.Repository` for the provider authorization aggregate, encrypted
credential reference, and owner bindings. A SQL host can implement the repository as one
transaction. A host that splits database and vault storage must implement an idempotent,
recoverable saga behind the same interface.

Use `domainkit/testing`'s in-memory repository in tests only. It does not encrypt credentials or
provide production durability.

## 3. Mount provider connection routes

An interactive provider connection has two server routes:

1. The start route checks the current user and tenant, creates a short-lived continuation, and
   returns a provider authorization URL.
2. The callback route checks the same authority, consumes the continuation exactly once, exchanges
   the provider code, and commits the durable authorization aggregate.

A token route validates the submitted credential on the server and commits the same durable
aggregate without a redirect.

After connection, reconstruct the provider client from the stored credential and non-secret
provider context. Do not ask the browser to retain the provider token or account client.

## 4. Persist plan attempts before approval

When the user asks to review DNS changes:

1. Load the authorized connection and assert its owner/domain grant.
2. Reconstruct the provider.
3. Create the plan against an exact zone or a discovered zone.
4. Persist the complete encoded plan, digest, connection, tenant, domain, and expiry as one attempt.
5. Return a browser-safe projection for review.

When the user approves, correlate the submitted digest with that server-owned attempt before calling
`Provisioning.authorize`. Do not rebuild a plan from browser input and treat it as the reviewed
artifact.

## 5. Apply once and persist the receipt

Before apply, claim or otherwise serialize the plan attempt according to your host's request model.
Pass the persisted plan and authorization to `Provisioning.apply`. Store complete and partial
receipts before reporting the outcome.

An apply receipt is not merely UI progress. It is the proof needed to construct a future safe
cleanup plan.

## 6. Map authenticated endpoints into React

Expose only application-facing operations to the browser, then adapt the client once:

```ts
import { Transport } from "domainkit";

export const transport = Transport.layerFromAsync({
  connection: api.connections,
  provisioning: api.provisioning,
  verification: api.verification,
  cleanup: api.cleanup,
});
```

The React transport carries a `planDigest`; your server can additionally correlate an opaque attempt
identifier in its authenticated session, database, or API route. The transport is a browser-safe
application contract, not a provider API.

## 7. Keep product readiness separate

`Verification.observe` reports provider and public-DNS evidence for DNS requirements. Your product
may also need provider-specific service readiness, certificate status, email verification,
polling/backoff, or a persisted onboarding phase. Keep that product lifecycle in the host instead of
flattening it into DomainKit's observation result.

## Security checklist

- Provider credentials are accepted and used only on trusted server boundaries.
- Every connection, reuse, plan, apply, cleanup, and disconnect route rechecks tenant authority.
- Domain grants are checked in addition to provider scopes.
- Interactive continuations are single-use and bound to the initiating flow.
- Plans and cleanup plans are authorized by exact digest.
- Partial receipts are stored before a retry or remediation path begins.
- Removing one domain grant does not imply deleting DNS records.
- Final-binding revocation remains retryable until the provider confirms it.

## Next steps

- [Provision and clean up records](/docs/guides/provision-and-clean-up)
- [Choose a React integration level](/docs/react/integration-levels)
- [Understand provider authorization and grants](/docs/core/connections)
- [Review the transport reference](/docs/reference/transport)
