User journeys
Map every user-facing CustomDomain™ flow to the surface that implements it: widget for end customers, console and API for developers, and MCP for AI agents.
The completeness map: every user-facing flow and the surface that implements it.
Personas
- Developer / operator: integrates the product, works in the console and via the API.
- End customer: the SaaS's customer connecting their own domain, works in the widget.
- Platform operator: runs and monitors the stack.
End-customer journeys (widget)
| # | As a customer, I want to… | Surface / path |
|---|---|---|
| C1 | Enter my domain and have its DNS provider detected | Widget → Domain analysis (POST /v1/domains:check) |
| C2 | Connect automatically when possible | Widget → sign in with the provider (oauth:start → callback), one-click setup (domainconnect:start) or secure sign-in (browser:start) |
| C3 | Get exact records to add when manual | Widget → Manual config from GET /v1/connections/{id}/records (copy buttons) |
| C4 | Enter a scoped provider credential to auto-write | Not in the widget, which asks for no key; the console and the API take an API key (POST /v1/connections/{id}/apply) |
| C5 | See progress until my domain is live | Widget → In progress (polls status) → Success |
| C6 | Recover from errors / switch to manual | Widget → Error screen (retry / switch) |
| C7 | Not lose my place accidentally | Widget → exit-confirm + session-expired overlays |
| C8 | Forward my setup to a colleague to finish | Widget → Share (loadSharedFlow, POST /v1/sharing/connect → GET /share/{token}) |
| C9 | Buy a new domain from within the widget | Widget → Buy (purchaseDomain, POST /v1/registrar/checkout → /fulfill) |
Developer journeys (console + API)
| # | As a developer, I want to… | Surface / path |
|---|---|---|
| D1 | Create and manage applications | Console → Applications and each application's page (POST/GET /v1/applications, GET/PATCH/DELETE /v1/applications/{id}, its keys and connect target) |
| D2 | Create, list, and revoke API keys | Console → API & SDK → API keys (POST/GET/DELETE /v1/applications/{id}/keys) |
| D3 | Invite teammates and set roles | Console → Team (POST /v1/members, PATCH /v1/members/{id}, :accept) |
| D4 | Connect a domain from the console | Console → Domains (POST /v1/connections) |
| D5 | Inspect a connection and drive it | Console → Domain detail, for a domain of any application (GET /v1/connections/{id}, /records, the apply rails, all with the tenant API key) |
| D6 | See which providers auto-configure | DNS providers in these docs, or the public GET /v1/providers and /v1/providers/census (the console has no providers page; each domain's detected provider shows on Domains) |
| D7 | Receive events and inspect deliveries | Console → API & SDK → Webhooks to register and delete endpoints, and Activity for the timeline of deliveries (POST/GET/DELETE /v1/webhooks, GET /v1/webhook-deliveries) |
| D8 | Track usage against quota | Console → Usage (GET /v1/billing/usage) |
| D9 | View and change plan | Console → Billing (GET /v1/plans, POST /v1/billing/checkout, /portal) |
| D10 | Embed the widget safely | Console → Widget (Install, Design, Try it live). Your server mints the token: POST /api/widget-token with an API key (console applications) or POST /v1/tokens with the client secret (applications created over the API). The widget JWT is app- (and optionally domain-) scoped |
| D11 | Buy a new domain, money-safe | Console → More → Buy a domain (/app/sell: search → in-page checkout authorizes → registration → capture; auto-connected) |
| D12 | Resume an abandoned setup | Console → Domains → Finish setup (reopens the guided flow at the right step) |
| D13 | Point an agent at the MCP server | Console → More → MCP server (/app/mcp: endpoint, client setup for Claude Code, Claude Desktop, Codex, Cursor, VS Code, ChatGPT and others, a connection test). Switch it on under Settings → Features |
| D14 | Review and revoke what agents may do | Console → More → Agents (/app/settings/agents: each grant's agent, application, last use and scopes, with Revoke). It switches on after your first approval on the consent page (/agent/consent) |
AI-agent journeys (MCP)
An agent drives domains through the MCP server, hosted at
https://mcp.customdomain.ai/mcp, which wraps the same /v1 API with twenty-three tools.
A person approves what the agent may do first: see
Agent access.
| # | As an agent, I want to… | Tool |
|---|---|---|
| M1 | Check if a domain is available and priced | search-domain-availability |
| M2 | Suggest available domains from keywords | generate-domain-suggestions |
| M3 | Register a domain (fail closed behind an authz callback; off on the hosted service) | create-domain-order → check-order-status |
| M4 | Connect a domain the user already owns | connect-domain → check-connection-status |
| M5 | See how a domain can be configured before acting | discover-provider |
| M6 | Forward a domain to another URL (301) | forward-domain → check-connection-status |
| M7 | Set up email (MX/SPF/DKIM/DMARC) for a domain | add-email → check-connection-status |
| M8 | Re-apply a managed connection, or take any connection down (the person confirms the domain first, and the grant needs domains:disconnect) | reapply-connection / disconnect-domain |
| M9 | See every connected domain and its status (page by page when the list is cut) | list-connections |
| M10 | Check a domain's HTTPS certificate | check-certificate-status |
| M11 | Find out why a domain is not live, then re-run the check after the fix | diagnose-connection → recheck-connection → check-connection-status |
| M12 | Find out whether the workspace may connect new domains | check-billing-status |
| M13 | List the domain purchases | list-domain-orders |
| M14 | Move a domain's nameservers to the application's DNS host, follow the move, and move them back (the person confirms first) | migrate-nameservers → check-nameserver-status / rollback-nameservers |
| M15 | Use a key the workspace already keeps instead of starting a new sign-in (the person confirms first, and the grant needs domains:connect) | list-provider-accounts / find-saved-access → use-saved-access → check-connection-status |
Platform-operator journeys
| # | As an operator, I want to… | Surface / path |
|---|---|---|
| O2 | Serve HTTPS for live domains automatically | Edge on-demand TLS gated by ask |
| O3 | Provision tenants for signups | POST /v1/tenants:provision (provision secret) |
| O4 | Keep tenants isolated | Tenant-scoped handlers; cross-tenant → 404 |
| O5 | Keep secrets safe | Hashed keys, provider credentials used once or kept encrypted, sealed console key, no key material in logs |
Coverage note
The setup_type values automatic and manual (plus the sign-in, one-click
setup and secure sign-in rails, and DNS hosting where the application offers it)
are the paths the widget drives today, and the API key way belongs to the
console and the API; async additionally
powers managed connections, and mcp
covers agent-driven setup through the MCP server. A connection
can be disconnected with DELETE /v1/connections/{id} (reverting a managed template
first); see
Offboarding.
Choosing a custom-domain solution (2026)
An evaluation guide for custom-domain onboarding: build vs. buy, what "provider coverage" really means, and the questions to ask any vendor including us.
How the connect flow works
How a domain goes from create to apply to live, and the six ways in: provider sign-in, one-click setup, secure sign-in, an API key, the records or DNS hosting.