AI-powered · Brand-controlled · Progressive streaming

Your customers find their perfect domain in seconds

A standalone service that drops alongside any existing webshop. Each brand gets its own server-side config — TLD catalog, market bias, premium on/off. The AI generates concept-aware candidates, checks live availability, and streams results progressively.

< 4s
First result
20–40
AI candidates
32
Domains/batch
10+
Brands supported
What you sell — candles, software, coaching Who it's for — pet owners, freelancers, families The vibe — sustainable, premium, budget-friendly
Try:

1. AI generates candidates

Two rounds produce 20–40 candidates: creative brandable names unique to your concept, and short keyword names for the core business — all scoped to your brand's TLD catalog.

2. Results stream live

Batches of 32 are checked in parallel. First result appears within ~4 seconds — each batch streams as it resolves so your users see domains load progressively, not all at once.

3. Premium — per brand

Premium detection is enabled per brand. When on, registry pricing surfaces inline from the availability check — no second lookup. When off, only standard available domains are returned.

Integrations

Ship in minutes, not weeks

Native integrations for the platforms your brands run on. No custom code required to go live.

WordPress plugin · Basket API

Works with OneWebshop

Via the WordPress plugin.

The WordPress plugin includes a Basket API integration that works with OneWebshop-compatible checkouts (GravityVault / Uniweb). Install the plugin, enter your shop's basket API URL in settings, and the "Add to cart" button on each domain result will fetch the current TLD plan and price, add the domain to the customer's basket, and redirect them to checkout — all from within the WordPress widget. No custom backend code required.

Live TLD pricing
Plugin fetches current TLD plan UUIDs and prices from the basket API on page load — always up to date
Optimistic cart UI
Button shows "Added" instantly; the basket POST runs in the background and redirects on success
Server-side proxy
All basket API calls go through the PHP proxy — API keys and tenant headers never reach the browser

WordPress plugin

Drop-in shortcode for any WordPress site

Place [ai_domain_search] on any page or post. The admin panel covers everything: brand colours with live preview, five card border styles, 1–4 column grid, max-results snapped to column count, and localisation in EN / NO / FI / DE.

How results are ranked

SSE delivers domains in CNR batch-arrival order (random). When the stream ends, results are re-sorted client-side by relevance score — best match surfaces first. Scoring per domain name:

  • +word.length × 4 for each query word (≥3 chars) found in the domain name
  • +15 compound bonus when 2 or more query words match
  • +up to 10 efficiency — matched characters ÷ name length (rewards tight, exact matches)
  • +5 locale TLD nudge — .no for Norwegian, .fi for Finnish, .de for German, .com for English

Example: query "onkel edvins bodega" (locale=no) — edvinsbodega.no scores 78 (two word matches + compound + efficiency + .no nudge) and ranks first over onkeledvins.com at 69.

Button actions
  • Open URL — redirect with {{domain}} placeholder
  • WooCommerce — add to cart with domain as order metadata
  • JavaScript event — aisds:domain_selected on document
  • Basket API — GravityVault / Uniweb compatible with optimistic UI
WordPress 6.0+ PHP 7.4+ · cURL WooCommerce optional

Custom integration

Any stack — REST or script embed

For teams with their own frontend: a single POST /suggest returns an SSE stream — merge results into your existing domain list as they arrive, dedup by name, and your existing result wins on conflict. No npm, no build step. Or embed the lightweight JS snippet from the webshop integration guide with three config values.

What you get
  • SSE stream — one JSON object per domain, no batching to handle
  • MCP tool for AI agents — suggest_domains collects into a list
  • Premium detection inline — price + renewal in the same event
  • API key stays server-side — never touches the browser
What makes it different

Built to fit. Not to replace.

A standalone service you drop alongside any existing stack — no schema changes, no shared database, no framework lock-in.

Brand-controlled configuration

Each brand gets its own YAML file: TLD catalog, market bias via primary_tlds, and a premium_enabled toggle to turn premium detection on or off. ccTLD entries in primary_tlds also drive language bias — set .no and the AI generates Norwegian names; set .de for German, .nl for Dutch, and so on. Changes take effect within 60 seconds — no image rebuild, no redeploy. Unicode (IDN) domain names are returned as readable display names like bjørn.no.

docs/CONFIGURATION.md →

AI that understands the concept

The LLM generates two types of candidates from the user's natural-language description: creative brandable names unique to the concept, and short keyword names that describe the core business. Two rounds per search produce 20–40 candidates scoped to the brand's TLD catalog. Progressive streaming means the first result appears within ~4 seconds — not after the full search completes — so users see suggestions loading in real time.

docs/DEVELOPER-INTEGRATION.md →

One API call — REST or MCP

A single POST /suggest opens a server-sent event stream. Results arrive domain by domain as each availability batch completes. The same service exposes an MCP tool for AI agents — same logic, same brand config, no duplication. For webshop teams: embed a script tag with three config values (no npm, no build step), or proxy through your backend in a few lines of Node.js or PHP to keep the API key server-side.

docs/WEBSHOP-INTEGRATION.md →

Rate-limited and hardened

Per-brand rate limiting prevents abuse across shared infrastructure — each brand's key has its own request budget with no shared ceiling. The prompt pipeline validates and sanitizes input to block prompt injection attempts before they reach the model. Runs as a single Docker container; brand YAML configs mount as a read-only volume — no image rebuild to onboard a new brand. API keys never appear in logs or error responses.

docs/IMPLEMENTATION.md →

Redis-backed caching

Identical queries within the cache window replay instantly — no LLM call, no CNR round-trip. Set REDIS_URL to use a shared Redis instance across multiple app containers; omit it and the service falls back to in-process memory automatically. The Docker Compose stack ships a pre-configured redis:7-alpine service with AOF persistence, so cache entries survive container restarts. TTL is configurable via QUERY_CACHE_TTL_SECONDS.

docs/CONFIGURATION.md §6 →

Circuit breakers & structured observability

Circuit breakers are scoped per brand — one brand's failures cannot open the breaker for others. Both LLM and CNR breakers open independently after a configurable threshold and recover via a timed half-open probe. All logs emit as single-line JSON with ts, level, latency_ms, and cache_hit fields, ready to pipe into any log aggregator. GET /health returns brand count and uptime; GET /metrics exposes per-brand circuit states (admin-gated).

docs/IMPLEMENTATION.md →
API Reference

Try it yourself

One POST request. Results stream back as Server-Sent Events — one JSON object per line as each domain resolves.

POST /suggest
# cURL
curl -N -X POST https://ai-domain-search.digitalfoundation.one/suggest \
  -H "Content-Type: application/json" \
  -H "X-Brand-Api-Key: <your-key>" \
  -d '{"query": "indie coffee roastery"}'

# Request body
{
  "query": "indie coffee roastery"
}

The -N flag keeps curl open to receive the stream. Replace <your-key> with the brand API key from your YAML config.

200 SSE stream
# Standard domain — available, not premium
{
  "domain":      "beanroasters.no",
  "is_premium":  false
}

# Premium domain — includes reg + renewal price
{
  "domain":                "coffee.shop",
  "is_premium":           true,
  "premium_price":        "299.00",
  "premium_renewal_price": "95.00",
  "premium_currency":     "USD"
}

# Stream always ends with a done sentinel
{ "done": true }

Domains stream as they resolve — no waiting for all 20. On your side: push each result into your existing domain list as it arrives. Dedup by domain name — your own check wins on conflict.

Field Type Always present Description
domain string Yes Fully qualified domain name, e.g. coffee.shop
is_premium boolean Yes True if the registry classifies this as a premium domain
premium_price string When premium Registration price (decimal string). Includes brand markup if configured.
premium_renewal_price string When premium Annual renewal price at registry rate (no markup applied)
premium_currency string When premium ISO 4217 currency code for both price fields, e.g. USD
done boolean Last event only Stream terminator — close the connection when you receive this