Buying a domain
Buy a new domain in the console with live pricing: the money-safe flow that authorizes, registers, then captures payment, and how it becomes a connected domain.
You can buy a brand-new domain without leaving the console, under Buy a
domain in the console sidebar (/app/sell). Search a name to see availability with live retail
pricing (the renewal price is shown up front), then register it in a couple of
clicks. The platform resolves which upstream registrar fulfills each TLD; that
choice isn't shown in the buying flow and doesn't change anything for you; the
domain is managed here either way.
Shop-style search
Searching a name surfaces more than the exact match. Results come back in three grouped sections:
- Exact match: the name you typed.
- Other endings: the same name on other TLDs
(
.com .net .org .io .co .ai .app .dev .xyz .me). - Similar names: close variants of the name (common prefixes and suffixes,
e.g.
get-,try-,-app,-hq) on the primary TLD.
Each result shows availability and a live price. To get grouped suggestions from
the API, pass ?suggest=1 on the search request; every result then carries a
Kind field (exact, tld, or variant) that the console uses to group
them. Without suggest=1 the endpoint returns the exact name only. See the
Registrar API reference.
The money-safe flow
The purchase is ordered so you can never pay for a domain you don't get:
- Search & price: availability and a live retail quote per domain
(
GET /v1/registrar/search,POST /v1/registrar/quote; see the Registrar API reference). - Authorize: a checkout on the page, in place of the search results (no pop-up and no off-site redirect), shows the order and collects the card, and authorizes the amount. Nothing is charged yet. Back to search puts the results back as you left them.
- Register: the platform registers the domain server-side, driven by the Stripe webhook; the browser returning to the console is only a fallback trigger, so closing the tab doesn't strand the order. Fulfillment is idempotent per checkout session: a retry or reload can't register or charge twice.
- Capture: only after the registration succeeds is the card actually charged. If registration fails, the authorization is released and you pay nothing.
A completed purchase fires the domain.purchased
webhook; a failed registration fires
purchase.error.
After the purchase
A purchased domain behaves exactly like a domain you brought yourself:
- it appears in the Domains console automatically;
- it is auto-connected: the fresh zone gets an apex record pointing
where your application sends its domains: the
edge, or your own infrastructure's hostname (an
ALIASorArecords, whichever the registrar accepts at the apex; on your own infrastructure theArecords go to yourapex_ipv4), so the connection starts movingpending → propagating → liveimmediately, with no setup step; - it is manageable via the same connections API: records, status, webhooks, and offboarding are identical.
Buying through the embedded widget
The same money-safe flow is available to integrators embedding
the widget, not just console users. Call
window.customdomain.purchaseDomain(config) to open the in-widget buy screen;
once your end user picks a domain, the widget starts a real checkout
(POST /v1/registrar/checkout) and fires a customdomain:purchase event
carrying a Stripe session. Mount Stripe Embedded Checkout (or redirect) with
its clientSecret / url, then finalize with POST /v1/registrar/fulfill,
which registers the domain, captures the charge, and auto-connects it, exactly
like the console flow above. See the
SDK reference for the event
shape and the
Registrar API reference for
both endpoints.
Who can buy
Starting a purchase (POST /v1/registrar/checkout) ends in a new connection, so
it follows the same billing rules as connecting a domain. A workspace without a
trial or subscription gets 402 billing_required before anyone pays, except
while it still has free domains (the first
ten), which go through without a card. Search and pricing are reads and stay open.
Availability
Buying is live on the hosted service. The purchase engine is fail-closed:
in any environment where SELL_PURCHASE_ENABLED, a registrar credential, and a
Stripe key aren't all configured, purchasing returns 503 rather than taking
an order it can't fulfill. Search and pricing work independently of the
purchase gate. A purchase that takes no payment (POST /v1/registrar/purchase)
has its own switch, SELL_DIRECT_PURCHASE_ENABLED, and is off on the hosted
service: every purchase there goes through checkout.
The MCP server has a create-domain-order tool, but
purchases through MCP are off on the hosted service. The tool is gated by a
purchase authorization callback
as well as by the direct purchase switch, and the hosted service configures no
callback, so it answers rejected. Agents can still read orders with
check-order-status and list-domain-orders.
Serve customer domains from your app (reverse-proxy edge)
Turn on edge serving so customer domains reach your app: set an origin, use X-Forwarded-Host to tell domains apart, and debug 421, 502 and 402 errors and loops.
How the widget works
Learn how customdomain-js adds a drop-in modal for connecting a domain, how a widget JWT keeps keys out of the browser, and the screens a customer sees.