Domain Search, Purchase and Connect

Download skillThe skill is a reference md and part of wix-manage skill. You can use the following command to add the full wix-manage skill to your project:
Copy

One document, four parts. Section numbers carry their part's letter, so every reference names the part it points into — §A4b, §P3, §C0c, §R4.3.

PartSectionsCovers
Part A — Entry and Routing§A1 – §A8Intent, availability, suggestions, and the routing decision. Start here.
Part P — Purchase Path§P1 – §P10Buying a domain from Wix
Part C — Connect Path§C0 – §C7Connecting a domain the user already owns
Part R — Reference§R1 – §R9Endpoints, product IDs, URL templates, site resolution, ownership lookup, error handling

Before any API call, read Part R. It holds every endpoint, product ID, URL template, site-resolution rule and error rule used by all three of the other parts. Do not guess a URL or a field name — look it up there.


Part A — Entry and Routing

Part A takes the conversation from the user's first message to the point where two things are known: which domain, and buy or connect. Then it goes to one of two places:

Then go toFor
§P1The user is buying a domain from Wix
§C1The user already owns the domain and wants it on their Wix site

Covers US-01 – US-12. §A4b routes US-40 / US-41, and decides whether the connect path may perform the connection itself (US-42 – US-45) or only hand over a link. §A3.1 handles subdomains (US-48 – US-50), which skip the availability check entirely.


A1. When To Use This Skill

The user wants to:

  • Buy / purchase / register / get a domain
  • Search for an available domain, or check if one is available
  • Brainstorm a domain name from a business idea
  • Connect / assign / add a domain to their Wix site
  • Connect / assign / add a sub domain to their Wix site
  • Get a custom domain for their Wix site

Typical openers: "buy me a domain", "I want to purchase a domain", "get me mybusiness.com", "I need to connect coolbrand.com to my site", "I need to connect a domain mybakery.net to my Wix site", "I have coolbrand.com and want to connect it", "I need a domain for my pancakes restaurant"."

If the user mentions anything domain-related, this is the right flow. Asking a clarifying question is expected behaviour, not a dead end — stay here and ask. Only leave for requests that are completely unrelated to domains ("change my site colors", "how do I add a blog").

UX rule for everything below: keep it natural, never expose internal mechanics, and reveal information only when it changes what the user has to do next. See §R9.


A1.1 ⛔ Out of Scope — Hard Boundary

This skill sells Wix domains and connects domains to Wix sites. That is the whole job. It has exactly three information sources: check-domain-availability, suggest-domains, and the authenticated Wix endpoints in §R4.2. Nothing else.

Never do any of these, even if you have the tools and the user would find it useful:

❌ NeverWhy
WHOIS / RDAP lookups, or any registrant researchNot a source this skill uses. It also surfaces named individuals and addresses into a shopping conversation.
Name the owner of a domain, their company, city, or registrarSame. A taken domain is taken — who holds it is not the user's next step, and it is not yours to publish.
Advise buying a domain from its current owner — outreach, brokers, escrow, Sedo/Efty, acquisition emailsWix does not broker aftermarket sales. This is a different product, and a taken domain is a dead end here, not a negotiation.
Estimate what a domain is "worth", or quote four-to-five-figure rangesPure invention. The only prices in this skill come from the offering call.
Give trademark, legal, or brand-conflict adviceNot this skill's job and not reliable from a domain lookup.
Hand-write a list of alternative TLDs (.io, .dev, .app, …)Suggestions come only from suggest-domains. A list you composed yourself is invented data, whatever it happens to score on availability.
Search the web, browse the domain, or inspect the site running on itNone of it changes what the user does next: buy an available domain, or connect one they own.

If the user explicitly asks for one of these — "who owns it?", "can you help me buy it from them?" — decline in one sentence and return to the branch you were in:

I can't help with buying a domain from its current owner — I can only register domains that are available. Want to look at some alternatives?

A taken domain has exactly one shape of answer in this skill: whichever §A4b branch applies. Nothing may be added to it.

The one lookup that is allowed on a taken domain is the ownership check in §A4b — and it asks a single question: is this domain in the user's own Wix account? That is not registrant research. It searches what the user already has, it returns nothing about anyone else, and everything in the response beyond the match and the site name is off limits (§R4.3).


A2. Intent Classification (US-01, US-02)

Two things to establish: the domain and the intent.

SignalIntentNext
"buy", "purchase", "get", "register", "new domain"PURCHASE§A3
Wanting a domain — indefinite article, no domain named: "I want a domain for my site", "I need a domain for my pancakes restaurant"PURCHASE§A3
"connect it to my site", "assign it to my site", "bind it to my site", "point it at my site", "put it on my site"CONNECT → a site§A3
"connect it to Wix", "add it to Wix", "bring it into Wix", "I have", "I own", "transfer it over"CONNECT → Wix§A3
A specific domain, no buy/connect wordUNKNOWN§A3 — the availability check in §A4 settles it
Neither, and no domainUNKNOWNAsk: "Would you like to purchase a new domain or connect one you already own?"

The two senses of "connect" (US-51)

Both are CONNECT, and they name different targets. Read which one the user said — it is the difference between two different operations:

The user saysThey meanThe operation
to a site — and assign and bind are the same request in other wordsThe domain is already in the Wix account; which site should it serve?The bind — §R4.4
to Wix, add to WixThe domain lives at an outside registrar and is not in the account at allThe connect link — bringing it in, §C3

Nothing can be assigned to a site until the domain is in the account, so the second is the precondition of the first, not an alternative to it.

The account decides which one is actually possible, and it overrides the phrasing. §A4b looks the domain up before any message goes out, so let the lookup settle it:

  • Not in the account (§A4b-C)to a site cannot run, however plainly it was asked for; the bind gate wants the domain in the account first. The connect link is the answer to both phrasings.
  • In the account, unassigned (§A4b-B)to Wix is already true. Read it as to a site and offer the bind.
  • In the account, on a site (§A4b-A) — both phrasings are already satisfied; §C0 decides whether anything is left to do.

Never correct the user's wording. They are describing an outcome, not calling an API. Act on what the account says is possible and say what you did — do not explain that they used the wrong verb.

The article does most of the work: a domain is one the user does not have yet (purchase); my domain, or a named domain plus "I have" / "I own", is one they already hold (connect). Do not fall through to the clarifying question just because the words "buy" or "purchase" are absent — "I want a domain for my site" is a purchase.

An answer of "connect" / "I have one" with no domain named → ask "What domain would you like to connect?", then go to §A4.

Do not ask "do you already own this domain?" — not before the availability check, and not after it either. Asking first produces the awkward case where the user claims to own a domain that is not even registered; asking afterwards is redundant, because §A4b looks the domain up in their account and answers it without a turn of conversation.


A3. Do We Have a Domain? (US-03, US-04)

Take the first row that matches, reading top-down. A domain the user named wins over everything else in this table — including a site they named in the same breath.

SituationAction
User named a specific domain — even if they named a site tooNormalize it (§R1). A subdomain → §A3.1. Anything else → §A4, first, before any site work
User gave brand/business context but no domain — "My business is called Green Sprout Bakery", "I need a domain for my pancakes restaurant"Do not ask. Build a query from that context → §A5
No domain, but they pointed at a site"I want a domain for my wix site", "I need a domain for my site"Do not ask for a domain yet. The site is the context → §A3.2
Nothing at all — "I want to buy a domain", "help me get a domain"Ask, verbatim: "What domain do you have in mind?" Then take the answer as either a specific domain (→ §A4) or a description (→ §A5).

The user answering with a description rather than a domain ("Something with 'cozycuts' in it") is normal — treat it as a query and go to §A5.

⚠️ A named domain is checked before anything else happens, and the answer is the first thing the user hears. No site resolution, no fetching list of sites, no plan check and no list of sites comes in front of it. "I want to buy mybakery.com for my Wix site" names a site, and the site waits its turn: §A4 runs, the user is told "mybakery.com is available!" or "mybakery.com is already registered.", and only then does §P1 resolve the site. Asking which of ninety-three sites to use before saying whether the domain can even be bought answers a question the user has not reached yet.

A3.1 The Domain Is a Subdomain (US-48, US-49, US-50)

§R1.1 identified the host as a subdomain — shop.maximz.fr under maximz.fr.

Do not call the availability endpoint. A subdomain is not separately registrable, so there is no availability answer to be had and §A4 has nothing to do here. Ownership is the only open question, and it is usually already settled by the account.

A3.1a — the two lookups (silent)

Run the §R4.3 pair keyed on the subdomain. Only if neither array holds an exact match, run the same pair again keyed on the root domain.

Exact match atStateNext
Subdomain in sites[].primary or sites[].redirects[]Already connected§A4b-A, unchanged
Subdomain in domains[] (unassigned)ConfirmedGo to §C1 and follow it
Root domain in either arrayConfirmed via root§A3.1b
NeitherRoot is not in the account§A3.1c
User is logged out, or both calls fail after the silent retryUnknown§A4b-C, unchanged

A root match confirms the subdomain. The account that holds maximz.fr is the account that decides what sits beneath it — there is nothing left to ask, and nothing to hedge about.

A3.1b — the root is in the account (US-48)

Ownership is confirmed, so the "If it's yours" hedge does not appear. Say why it is confirmed, because the user asked about the subdomain and the account matched something else:

Go to §C1 and follow it — ownership confirmed via root. The opening in §C3 names the root; the link is the whole answer, and no bind is offered.

q= on that link carries the subdomain. The root is what proved ownership; the subdomain is what gets connected. The two are never swapped.

Carry the root's site if the account named one, as a candidate and not a decision. A root match under assigned names the site the root is on — which site should serve the subdomain is a separate question and this lookup did not answer it. §C1, Case R asks it. Do not resolve it here, and never let it reach a link unconfirmed.

A3.1c — the root is not in the account (US-49)

Say, verbatim:

{subdomain displayName} sits under {root displayName}, and I don't see {root displayName} in your Wix account. Would you like to connect {root displayName} first?

  • Yes → treat the root domain as the domain in hand and go to §A4, from the availability check onward. The subdomain comes after, once the root is in the account.
  • No, or any question about why → §A3.1d.

A3.1d — they ask why, or decline (US-50)

Both reactions get the same answer, once:

Authorization for a subdomain follows its root domain, so having {root displayName} in your account is what lets you control which subdomains are allowed to point at your sites. Connecting it is a formality — you don't have to change any DNS, and nothing about how {root displayName} works today has to change.

Then leave the offer open and say nothing more about it.

  • They change their mind → §A3.1c's yes branch.
  • They still declinego to §C1 and follow it — ownership asserted. Link only, no bind. Ownership was never established here, so this is the one subdomain branch where the "If it's yours" hedge is correct and stays.

State the recommendation once. A user who has declined twice has decided. The subdomain link is a working answer without the root, and repeating the case for it turns a recommendation into a pitch — §R9.

A3.2 The User Pointed at a Site but Named No Domain

This section is only for a message that named no domain. If a domain was named as well — "buy mybakery.com for my wix site" — row 1 owns it: §A4 runs first, and the site is resolved afterwards by §P1. Resolving a site here would put a list in front of the availability answer.

"I want a domain for my wix site" names no domain, and it is not nothing. Two things arrive with it, and the old reading of this row threw both away:

  • The site question is already answered. They want the domain on a site, so §R3's Case D question — "Would you like to connect this domain to one of your Wix sites?" — must not be asked. Asking it back is asking them to repeat themselves.
  • The site's name is brand context. §A5 takes free text, and a site called Green Sprout Bakery is exactly the query it wants. Never make the user type a business name the account already knows.

So resolve the site now, before the domain, and let it do both jobs:

Site resolution (§R3)Then
Case A — a siteId is in contextTake the site's name as the §A5 query. Suggestions and the site named, one message.
Case B — exactly one siteSame. Name the site so a wrong guess is visible.
Case B — several sitesAsk which one, with §R3 Case B's copy. That question has to be asked anyway, and its answer is also the query — §A5 runs on the reply.
Case C — not logged inNo account, so no site name to read. Do not front-load the login prompt — fall through to the "What domain do you have in mind?" row above. The site intent is remembered, so §R3's Case C prompt lands at its normal time, once a domain is in hand.
Case B — no sites at allNothing to name and nothing to connect to. Fall through to the bare "What domain do you have in mind?" row above, and treat the purchase as standalone.

Copy when a single site is resolved — §A5's list with its own opening:

Here are a few available options for {site name}:

  • greensproutbakery.com
  • greensproutco.com
  • sproutbakery.com

Want one of these, or do you have something else in mind? I can also show more options if none feel right.

⚠️ A site name is not always a business name. Auto-generated names (Evl 99faa20b7b2b, My Site 3, a bare hex string) and placeholders carry no brand signal, and querying §A5 on one returns noise. When the name has no real words in it, treat it as no context: keep the resolved siteId, then ask "What domain do you have in mind?" — the site still gets used for the plan check and the auto-connect line, just not for suggestions.

⚠️ This is the one place the purchase path resolves a site before the domain, and only because the user put the site in the request. §P1.1's rule — do not fetch list of sites unless the user asked about a site — is satisfied here, not bypassed. Carry the resolved siteId into §P1; the site is already settled, so the plan check is the next step and the question is never re-asked.


A4. Availability Check (US-07, US-08, US-09)

Check the normalized domain silently — no "let me check", no "one moment". Endpoint and response shape: §R4.1.

A4a — available: true (US-08)

Say, verbatim:

{displayName} is available!

Then:

  • Intent is PURCHASE or UNKNOWNNow go to §P1 and follow it. If a siteId is already in context, do not send "…is available!" on its own — continue straight into the site + plan outcome (§P1) in the same message.
  • Intent is CONNECT → the user cannot connect a domain nobody has registered. Say: "{displayName} isn't registered yet — did you mean you'd like to purchase it?"
    • Yes → go to §P1 and follow it.
    • No → "Do you own a different domain you'd like to connect?" → back to §A4 with the new domain.

When no siteId is in context but the user did ask for a site, the availability answer and §P1's site question belong in the same message — the answer first, the question behind it:

mybakery.com is available! You have 93 Wix sites. Which one should it go on?

  1. {site name}
  2. (§R3 Case B's forms decide how many)

One turn instead of two, and the ordering is still answer-then-question.

⚠️ Suppressing the standalone line is a merge, never a deletion. The user is told in plain language that the domain can be bought — exactly once, in the first message that follows the check. Both continuations carry it, and the merged forms live in §P1.3a and §P2.3, Premium and Free respectively. If you are about to send a message that offers a plan, a price or a bundle and the user has not yet heard "{displayName} is available!", the line was dropped rather than merged. Say it.

A4b — available: false (US-09)

The domain is registered. Registered by whom is the next question, and it decides everything that follows — so answer it before you say a word.

Step 1 — whose domain is it? (silent)

Call both ownership endpoints together, per §R4.3:

Copy

Compare the returned domain strings to {domain} exactlysearchTerm is a substring search and a partial hit is not ownership.

  • User is not logged in, or both calls fail after the silent retry → skip to §A4b-C. Ownership is unknown, which is what §A4b-C's copy already assumes.

This runs before the suggestions call and before any message. Alternatives are only fetched in §A4b-C. Fetching them first — as an earlier version of this skill did — means offering a user replacements for a domain they already own.

Exact match atBranch
sites[].primary.domainName, or sites[].redirects[].domainName§A4b-A — theirs, already on a site
domains[].domainName (unassigned)§A4b-B — theirs, not on a site yet
Nowhere§A4b-C — not in their Wix account

A4b-A — it is theirs, and already connected (US-40)

Read siteName from the same sites[] entry that matched. One message, then stop:

{displayName} is already connected to {siteName}.

No suggestions. No connect link — there is nothing to connect. No "if it's yours" — the account just said it is. Terminal state.

If the match came from redirects[] rather than primary, the domain is in use as a forward:

{displayName} is yours — it's currently forwarding to {siteName}.

If the user wanted it in the other role on that same site — forwarding today, but they asked for the site's address — this is not terminal after all. Ownership is confirmed and the domain is already on the right site, so the role can be changed: go to §C0b and follow it (US-45).

If the user asked to connect it to a different site than the one it is on, that is a move, and a bind performs it — binding the domain to the new site takes it off the old one. Do not compose the answer here, and do not ask "Want to move it to {requested site}?" on its own. That question hides the half of the change the user is not thinking about: the site the domain comes off, which may be losing its primary domain.

Go to §C0c and follow it, carrying the requested site and ownership confirmed. That section resolves the site, checks its plan, and asks for the move in a form that names both sites (§C3.2d) before anything is written.

A4b-B — it is theirs, and not connected to anything (US-41)

Ownership is settled, so there is no question to ask and nothing to hedge. Go to §C1 and follow it, carrying the domain and ownership confirmed.

This branch is the one that unlocks doing the work. A confirmed match is the first of the four conditions in §R4.4, so the connect path can offer to make the connection itself rather than only pointing at the dashboard. Carrying ownership as confirmed is what makes that possible; carrying it as asserted silently downgrades the user's outcome to a link.

That path resolves the site, checks the plan, and looks at what the site already has — §C1, §C2 and §C3.1 — and, on a Premium site, lands on an offer plus the link in one message:

{siteName}'s primary domain is {current primary}. Should {displayName} become the primary domain instead, or redirect to it?

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

On a Free site nothing is offered and nothing is written — it is the link plus the upgrade block, exactly as before.

§C0 – §C4 own all of this wording, including which of the three offer forms applies and the two confirmations in front of the write. Do not compose any of it here, and do not promise in Part A that the domain will be connected — that promise is only safe after §C2 has said Premium.

No suggestions, no "do you own this?", no "if it's yours".

A4b-C — not in their Wix account (US-09)

It cannot be purchased here — Wix registers available domains, it does not resell taken ones. This branch is short and closed.

⚠️ This branch is not "someone else owns it". A domain held at an outside registrar and never connected to a Wix site is invisible to the lookup, so the user may well own it. Never say or imply otherwise — see §R4.3.

Do exactly two things: call suggest-domains with the SLD only for 3 alternatives (§A5), then send one message containing only this:

{displayName} is already registered. If it's yours — you can connect it to a Wix site. Here are available alternatives that fit your brand:

  • theetzlenu.com
  • etzlenu.net
  • etzlenuco.com

That is the entire response. No registrar, no "someone renewed it six months ago", no valuation, no broker or outreach option, no TLDs you thought of yourself. If your answer to a taken domain is longer than the block above, you have left this skill — see §A1.1.

The "If it's yours" hedge is correct here and only here — either the ownership check found nothing, or it could not run. Ownership is a guess in this branch, and the copy says so honestly.

No connection is performed on this path. §A4b-B can offer to do the work because an account lookup proved the domain is the user's; here nothing proved it. Writing an unverified domain onto a live site fails the first condition of §R4.4, so the connect link is the whole of what this branch can offer — no primary-or-redirect question, no bind, however plainly the user says it is theirs. If they are right and the domain is theirs at an outside registrar, the dashboard is where that gets sorted out.

This holds even when the user asked to connect it "to my site" — or to assign or bind it there (§A2). That request names the bind, and the bind cannot run on a domain the account does not hold; bringing it into Wix comes first and the link is what does that. Give the link, and do not promise the site assignment as though it were about to happen. Do not lecture them about the order either: the link goes to the page where both steps are completed, so "you can connect it to a Wix site" is a true and sufficient answer.

The one thing that can change this: the user was logged out, logs in, and the ownership check runs for the first time (§C1, Case C). A match found then is a real §A4b-A or §A4b-B, and the offer comes with it.

The three alternatives are whatever suggest-domains returned, in the order it returned them. For etzlenu.com that is theetzlenu.com, etzlenu.net, etzlenuco.comnot a .io/.dev/.app list you assembled. Those may well be available; they are still fabricated output, because no call produced them.

Then branch on the reply:

  • Picks an alternative → that is the chosen domain, skip re-checking availability (US-06) → go to §P1 and follow it.
  • Says it is theirs / wants to connect → go to §C1 and follow it, carrying the domain, the fact that it is already known to be taken, and ownership asserted by the user (not confirmed — the account search did not find it).
  • Wants something else → back to §A3.

When the intent was already CONNECT, do not offer alternatives — a domain they cannot register is no use to them. Go straight to §C1 with ownership asserted. If the user is logged out, §C1 Case C asks them to log in; once they do, the ownership check in Step 1 can run and may upgrade the answer to §A4b-A or §A4b-B.

A4c — DOMAINS_UNSUPPORTED_TLD

→ §A6.

A4d — Any other failure

→ §R8. Retry once silently; the user should never learn a first attempt happened.


A5. Suggestions (US-04, US-05, US-06)

First page — exactly 3

Copy

Always paging.limit=3. Three options is the contract — never dump ten.

Query construction:

Coming fromQuery
A taken domainThe SLD onlymybusiness.commybusiness
An unsupported TLDThe SLD onlymyshop.wsmyshop
A business idea or brand contextThe description — pancakes restaurant, Green Sprout Bakery

Keep the query short — roughly 12–15 characters works best. Drop filler words (thebestflowershopintownbestflowers), collapse repetition (gevageva…geva), abbreviate (professionalpro).

Present them as a plain bulleted list of suggestions[].domain, then invite both a pick and more:

Here are a few available options that fit your brand:

  • cozycuts.com
  • cozycuts.co
  • cozycuts.net

Want one of these, or do you have something else in mind? I can also show more options if none feel right.

When the suggestions come from business context rather than a typed domain, open with "Here are a few available options based on your business name:" instead.

Rules:

  • Every suggestion returned is already available. Never re-check one. (US-06)
  • Never show a "premium" column or flag premium suggestions.
  • If the user stated a TLD preference, call out the fitting ones (.com general, .shop / .store e-commerce, .me personal branding).
  • No suggestions returned → ask the user for different or broader keywords.

"Show more" (US-05)

Offer more only when pagingMetadata.hasNext is true. To actually fetch them, repeat the same query and paging.limit=3 and add paging.cursor={pagingMetadata.cursors.next} from the previous response. hasNext alone does not page — without the cursor you get page 1 again.

Here are more available options:

  • greensproutbakeryshop.com
  • gsbakery.com
  • greensproutco.com

Repeat with each new cursor for as long as the user keeps asking.

After a pick

The picked domain is the chosen domain. Do not check its availability.

  • Intent PURCHASE or UNKNOWN → Now go to §P1 and follow it.
  • Intent CONNECT → the user is picking a domain to buy, not to connect. Treat as PURCHASE.

A6. Unsupported TLD — Split by Intent (US-10, US-11, US-12)

Detected as an HTTP 400 body with details.applicationError.code === "DOMAINS_UNSUPPORTED_TLD" — there is no availability object on this response. See §R4.1.

The message opens the same way for both intents:

We don't currently support .{TLD} domains.

What follows depends on intent — these two branches are different and must not be merged.

A6a — PURCHASE intent (US-11)

Fetch 3 alternatives with the SLD only as the query (§A5) and show them in the same message:

We don't currently support .ws domains. Here are some available alternatives:

  • myshop.com
  • myshop.net
  • myshop.co

User picks one → skip the availability check → Now go to §P1 and follow it.

A6b — CONNECT intent (US-12)

Do not show alternatives — a domain they do not own is no use for connecting. Ask for another domain instead:

We don't currently support .ws domains. Do you have a different domain you'd like to connect?

  • User gives another domain → normalize → back to §A4.
  • User has none → offer to buy one instead: "Would you like to look for a domain to purchase instead?" If yes → §A5, then §P1.

A6c — UNKNOWN intent

Treat as PURCHASE (§A6a), and let the alternatives list do the disambiguating.


A7. Routing Summary

Every branch of Part A ends in exactly one of these. Name the destination to yourself, then follow that section — do not improvise the next step from memory.

State reachedNext
Domain available, buyingGo to §P1 and follow it.
Suggestion pickedGo to §P1 and follow it.
Unsupported TLD, alternative pickedGo to §P1 and follow it.
Domain is the user's and already on a site (§A4b-A)Nowhere — terminal. One message, then stop. Unless the role is wrong (§C0b) or the site is wrong (§C0c — a move, which a bind performs).
Domain is the user's and unconnected (§A4b-B)Go to §C1 and follow it — ownership confirmed. A bind may be offered.
Domain taken and the user says it is theirs (§A4b-C)Go to §C1 and follow it — ownership asserted. Link only, no bind.
Connect intent, domain confirmed takenGo to §C1 and follow it.
Subdomain, root domain in the account (§A3.1b)Go to §C1 and follow it — ownership confirmed via root. Link only, no bind.
Subdomain, root not in the account, user accepts the root offer (§A3.1c)§A4 with the root domain as the domain in hand.
Subdomain, root not in the account, user declines twice (§A3.1d)Go to §C1 and follow it — ownership asserted. Link only, no bind.
Connect intent, domain not registered, user wants to buyGo to §P1 and follow it.
Persistent failure§R8 — escalation ladder, then the fallback link

Both paths restate their own entry preconditions — what has to be true on arrival.


A8. Fallback (US-38, US-39)

A call that fails twice is handled the same way everywhere in this skill — silent retry, then the escalation ladder, then the fallback link. §R8 is the rule, including the verbatim copy at each stage. Never expose an error code, endpoint or tool name in any of it.


Part P — Purchase Path

Entry preconditions — you arrive here from Part A with:

  1. A single chosen domain, already normalized, and
  2. Confirmation it is buyable — either available: true from the availability check, or it came from the suggest endpoint (suggestions are always available, never re-check one).

If either is missing, go back to §A3–§A6 and settle it first.

Terminal states — this path ends in exactly one of:

Terminal stateReached when
Checkout linkThe user completed registration details and the cart is built (§P9)
Bundle linkA Free-tier user chose plan + domain together (§P2)
Error fallbackTwo failed attempts — §R8

Read Part R before any call. Endpoints, product IDs and URL templates all live there.

Covers US-18 – US-32.


P1. Site and Plan Outcome (US-18, US-19)

P1.1 Resolve the site

Domain purchase does not require a Wix site. Apply the site-resolution rules in §R3 — Case A (siteId in context), Case B (logged in → fetch list of sites), Case C (not logged in → inline login prompt), Case D (logged in, ask once).

Do not fetch list of sites unless the user asked about a site or answered yes to the question.

  • No site resolved → skip §P1.2 and §P2 entirely. No premium check, no voucher check, no upgrade pitch. Go to §P3 as a standalone purchase.
  • Site resolved → keep siteId and the site's display name; go to §P1.2.

P1.2 Check the site's plan

Copy

Read payload.premiumState. allowedDomain = premiumState !== "FREE".

Do this silently. Record whether the site was Premium or Free here — §P7 compares against it.

P1.3a Premium site (US-18)

Say, verbatim:

Great — after purchasing, {displayName} will auto-connect to {site name}.

When the site was already known from context — which is exactly when §A4a suppressed the standalone "is available!" line — merge the two into one message:

{displayName} is available! After purchasing, it will auto-connect to {site name}.

Go to §P3.

P1.3b Free-tier site → §P2.


P2. Free-Tier Offer (US-19, US-20, US-21, US-22, US-23)

The site exists but has no Premium plan. The user gets a real choice: upgrade and take the domain as part of the plan, or buy the domain on its own.

P2.1 Is the TLD coupon-eligible? (US-20)

The "free for the first year" promise is TLD-dependent — never promise it blindly.

Copy

coupons_applicable: true → eligible. Anything else → not eligible. If the call is unavailable, fall back to the static TLD list in §R7.

P2.2 Is a Premium plan on sale? (US-21)

The getPremiumSale context call (wix.premium.store.v1.sales/GetSale) runs automatically.

  • Returns saleDetails with data → a sale is active. Useful fields: saleDiscount, saleEndDate, remainingDays.
  • Returns empty / no saleDetails → no sale. Say nothing about sales.

P2.3 Present the offer

If a siteId was in context, this message owes the user the availability line. §A4a held back the standalone "{displayName} is available!" so it could be merged into the site + plan outcome, and this is the branch that merges it — §P1.3a does the same job on a Premium site. Lead with it and let the rest of the copy stand:

{displayName} is available! {site name} doesn't have a premium plan yet, and connecting a domain requires one. Upgrade and you can get it free for the first year — or buy it on its own at full price and connect it after you upgrade. Want me to generate a bundle link?

The not coupon-eligible variant takes the same opener. The just-logged-in variant does not — that user came through the login prompt, which only ever appears after "is available!" has already gone out on its own.

Coupon-eligible TLD — verbatim:

{site name} doesn't have a premium plan yet, and connecting a domain requires one. Upgrade and you can get {displayName} free for the first year — or buy it on its own at full price and connect it after you upgrade. Want me to generate a bundle link?

Not coupon-eligible — the free-year clause would be false, so drop that clause and keep the rest:

{site name} doesn't have a premium plan yet, and connecting a domain requires one. Upgrade and you can connect {displayName} to your site — or buy it on its own at full price and connect it after you upgrade. Want me to generate a bundle link?

If a sale is active, append one line to whichever version you used:

There's also {saleDiscount}% off Premium plans right now — {remainingDays} days left.

If the user just logged in or created an account in response to the connect prompt (§R3 Case C), they have already said yes to connecting. Skip the question and deliver the offer with the link in the same message — the connect constraint still gets stated:

Welcome! Your new site doesn't have a premium plan yet, and connecting a domain requires one. Upgrade and you can get {displayName} free for the first year →

[Get domain free with a site plan](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bbundle%20URL%7D*original::{bundle URL})

Why the constraint is in the sentence. US-19 asks for an informed decision, and the fact that makes this a decision rather than an upsell is that the standalone route leaves the domain unconnected until the user upgrades.

Two things the copy is careful not to do. It does not list what Premium includes — §P10 still forbids that, and "connecting a domain requires one" is a constraint, not a feature pitch. And it frames buying alone as deferred, not forbidden: buy now, upgrade later, connect then. That is what actually happens, so "you can't" would be wrong.

P2.4 User accepts the bundle (US-23)

Here's where you can pick a plan and get {displayName} free for the first year →

Get domain free with a site plan

Use the full domain in domainName, the resolved siteId in siteGuid. When the TLD is not coupon-eligible, use the label [Get your site live at this domain] instead — do not promise a free year.

This is a terminal state. Stop here. Do not continue to §P3, do not build a cart.

P2.5 User declines the bundle (US-22)

Reply "No problem." and continue to §P3 as a standalone purchase. Do not re-pitch the upgrade.

Do not restate the connect constraint here either. §P2.3 put it in front of the choice, which is where it changes a decision. Repeating it after the user has decided is a second pitch wearing a warning's clothes.

Keep the siteId in memory — §P7 re-checks the plan, and the user may upgrade in another tab. But treat the purchase as standalone for now: no msid on the checkout link unless §P7 changes it.


P3. Registration Period (US-24)

Copy

Include the leading dot in tld.

  • Save products[0].productId — the cart needs it in §P8. Never hardcode it.
  • Render every entry in products[0].pricingDetails[] as a table, and only those entries.

Valid cycles are a subset of 1, 2, 3, 5 and 10 years, and the subset varies by TLD — some start at 2, some stop at 3, some go to 10. Do not add a row the API did not return, and do not drop one it did.

Sort the rows ascending by cycle.cycleDuration.count. The API does not return them in order — .org and .biz both come back 10, 5, 2, 3, 1. Rendering the array order gives the user a jumbled table.

Which fields — exactly three per row

Each pricingDetails[] entry carries several price objects. Read these and no others:

ColumnFieldVerified value (.biz, 1 year)
Durationcycle.cycleDuration.count + .unit1 YEAR1 year
You pay nowfinalPrice.total.formattedAmount$7.90
Renews atrenewalPrice.total.formattedAmount$35.90

Always formattedAmount — it arrives with the currency symbol and the right number of decimals. Never take amount and format it yourself, and never do arithmetic on either.

renewalPrice.total is the charge for the same period again — for a 2-year row it is the next 2-year charge, not a yearly rate. The header wording is what carries that; if it ever proves confusing, fix the header, do not add a footnote after the table.

⛔ Do not read these, all of which are in the same response and all of which will produce a wrong or unexplainable number: catalogPrice (the undiscounted list price — showing it next to "You pay now" invents a discount claim), initialPurchasePrice (identical to finalPrice.total in every row observed — if it ever differs, that is new information to check, not a free choice), lowestCyclePrice (its name and its value are consistent with two different meanings in the data observed, so it is unverified), and any monthly* or subtotal* variant. savings appears on some rows and not others — never render it.

Message shape — one row per returned pricingDetails[] entry and no other rows:

No problem. How many years would you like to register {displayName} for?

DurationYou pay nowRenews at
{cycle 1 duration}{cycle 1 finalPrice}{cycle 1 renewalPrice}
{cycle 2 duration}{cycle 2 finalPrice}{cycle 2 renewalPrice}
… one row per entry the API returned, shortest first …

At checkout, prices may be shown in your local currency.

(Open with "No problem." only when the user has just declined a site or a bundle. Otherwise open with "How many years would you like to register it for?".)

That closing line is fixed and it is required — this is the first place the user sees a price, and every message that shows one carries it. Wording and the full rule: §R10.

Ask the user to pick. If they have no preference, default to the shortest available period.

Why the renewal column is not optional. The first-term price is discounted and the renewal price is not — for .biz that is $7.90 now against $35.90 at renewal, a 4.5× step the user finds out about a year later. A single-price table is accurate and still misleading.

⛔ Never invent a price

Every number in that table comes from this response and this response only. There is no fallback price list anywhere in this skill or in your own knowledge. A .com does not have a price you already know.

SituationWhat to do
Call succeededRender its rows. Nothing else.
A row has finalPrice but no renewalPriceLeave that cell empty. Never fall back to catalogPrice, and never carry a renewal figure across from another row. Not observed in any response so far — if it happens, it is an unknown, and an unknown price stays blank.
No products returned"Wix doesn't support purchasing this TLD. Try a different extension like .com, .net, or .org." Then offer suggestions (§A5).
Call failedRetry once silently, then the escalation ladder (§R8).
Call cannot be made at all — no Wix session, no authenticated tool available in this channelStop the flow. Say: "I can't pull up live pricing right now. You can see current prices and register the domain here → https://manage.wix.com/account/domains" Do not continue to §P4.

That last row is the one that bites. When the offering call is unavailable, the tempting move is to show a plausible table and carry on — a fabricated price the user may act on. A missing price ends the flow; it never gets filled in from memory.

If you find yourself about to write $7.90, $14.95, or any other specific figure that did not arrive in an API response during this conversation, you are hallucinating pricing. Stop.


P4. Contact Details (US-27, US-28)

Copy

Address fields are flat on each contact — streetAddress, city, country, postalCode. There is no nested address object.

P4.1 Contacts exist (US-27)

Show them and ask for explicit confirmation. Never skip this — never assume.

I have your contact details on file — would you like to use these?

  • Name: John Doe
  • Email: john@example.com
  • Phone: +1.2125551234
  • Address: 123 Main St, New York, US 10001
  • Confirmed → §P5.
  • Wants different details → collect as in §P4.2.

P4.2 No contacts (US-28)

Ask for every field, one per line:

I'll need a few details to register the domain:

  • First name
  • Last name
  • Email
  • Phone (e.g. +1.5551234567)
  • Street address
  • City
  • Country
  • Postal code

Field rules:

  • Phone+{countryCode}.{number}, e.g. +1.5551234567, +972.533456789.
  • Country — accept a full name and convert to the 2-letter ISO code before saving ("Israel" → IL, "United States" → US).

The user may answer in a single line ("Alex Johnson, alex@cozycuts.com, +1.5032218800, 310 Oak Ave, Portland, US, 97201") — parse it, do not make them re-enter field by field.


P5. Save Contacts (US-29)

Do this immediately once contacts are confirmed or collected — before asking about privacy — so validation problems surface while the user is still thinking about their details.

Generate a random UUID as sessionId (wsess). It links the contacts to the cart; keep it, §P8 needs the same value.

Copy
Copy

Use the same contact for registrant, admin and tech — standard for individual registrations.

Validation errors (US-29)

Name only the fields that are actually wrong, in plain language. Never show the raw error, a field path, or a code.

There's an issue with one of your details — can you double-check this?

  • Email — doesn't look like a valid email address

Take the correction, retry the upsert, and carry on. Some TLDs need extra fields — .com.br an identification number, .it an entity type. If the error is about a TLD-specific requirement, explain what is needed and ask for it.

On success, go to §P6.


P6. Privacy Protection (US-25, US-26)

Present all three options, Privacy + DNSSEC marked recommended. Prices come from the offering call with the addon product type (§R4.2); match each returned product by its ID. If a price is not available, omit it — never invent one.

The addon response has the same shape as §P3's — one pricingDetails[] entry per cycle, with finalPrice and renewalPrice on each. The registration period is already chosen by the time you get here, so read the row whose cycle.cycleDuration.count matches the chosen term and take finalPrice.total.formattedAmount from it. Never sum, never divide, never take the 1-year row and multiply.

How would you like to protect your registration?

  • Privacy + DNSSEC (recommended) — Keeps your personal info off public records while also protecting your domain from being hijacked or redirected by attackers — {price}
  • Privacy only — Hides your personal contact info from public records — {price}
  • No protection — Your contact info will be publicly visible — Free

At checkout, prices may be shown in your local currency.

The currency note is required here too (§R10). It qualifies the two {price} figures and not "Free" — free is not a currency amount. So if neither priced option came back with a figure, this message shows no price at all and the note does not appear.

{price} carries the term, and the term is whatever the user picked:

Chosen term{price} reads
1 year{finalPrice}/yr
N years{finalPrice} for {N} years

/yr on a multi-year term is wrong here for the same reason it is wrong in §P9. The addon figure is the charge for the whole period — verified live: Privacy + DNSSEC comes back $12.90 for the 1-year cycle and $38.70 for the 3-year one. Writing "$38.70/yr" triples the price in the user's head. (Those two figures illustrate the shape and are never printed to a user — §P9's closing rule.)

{price} is whatever the addon offering call returned for that product ID. "No protection" is the only one whose price is known ahead of time — it is Free. For the other two: if you did not get a price back, drop the — {price} suffix and present the option without one. The same rule as §P3 applies — a figure you did not receive in this conversation is a fabrication, and the wording above is a template, not a price list.

ChoiceAddon product ID
Privacy + DNSSECf8211619-d9f6-4312-9d03-f2958bbd08aa
Privacy only22a84545-4ac0-4490-a434-45a1ebc479fb
No protectionb9d89ff0-f29b-4bfd-a3f0-6e34ae65120d

Addon product type for all three: b3d86a1d-9db3-4f69-bd54-c132808856b1.

The user may pick any of the three (US-26) — recommend, never push. "No protection" is a legitimate answer; accept it without a warning.


P7. Pre-Cart Premium Re-Check (US-30)

Run this only when a siteId was resolved in §P1 and the site was Free at that point. Skip it for standalone purchases with no site, and for sites already Premium.

The user may have upgraded in another tab while answering the questions above. Re-check silently, just before building the cart:

Copy
ResultEffect
Still FreeNothing changes. Standalone checkout, no msid.
Now PremiumTell the user, and add msid={siteId} to the checkout URL.

When it flipped to Premium, add one line to the final message — after "Setting up your order..." and before the summary:

Setting up your order...

{site name} is now on a Premium plan — {displayName} will auto-connect after purchase.

Here's your summary: …

Never mention the check itself, and never mention it when nothing changed.


P8. Build the Cart (US-32)

Use CallWixSiteAPI (with siteId) when a site is in play, otherwise ManageWixSite. Both carry Wix session auth — add no headers.

Three calls, in order, silently:

  1. Cancel the existing cartPOST https://manage.wix.com/_api/premium-cart/v1/carts/active/cancel · Body {} Succeeds even when there is no active cart. This is what stops leftovers from an earlier session ending up in the user's order.
  2. Get a fresh cartGET https://manage.wix.com/_api/premium-cart/v1/carts/active
  3. Add itemsPATCH https://manage.wix.com/_api/premium-cart/v1/carts/active/add-items
Copy
  • The addon cycle duration must match the domain's.
  • core: "true" goes on the domain line item only.
  • Include the addon line item for all three privacy choices, including "No protection" — it is a product, not an absence.
  • Never announce any of these three calls. The only thing the user sees is "Setting up your order...".

ConditionCheckout URL
A site is attached — Premium in §P1.3a, or flipped to Premium in §P7https://manage.wix.com/cart/checkout?msid={siteId}
Standalone — no site, or the site is still Free (US-31)https://manage.wix.com/cart/checkout

Final message:

Setting up your order...

Here's your summary:

  • {displayName} — {N} year(s) — {finalPrice} (renews at {renewalPrice}{term suffix})
  • {privacy option} — {N} year(s) — {finalPrice} (renews at {renewalPrice}{term suffix})

At checkout, prices may be shown in your local currency.

Here's your checkout link → [Complete your purchase](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bcheckout%20URL%7D*original::{checkout URL})

The currency note sits between the summary and the link, so the link is still the last thing in the message (§R10). This is the screen the user actually reads before paying, so it is the one place the note matters most.

For "No protection", the second line reads - **No protection** — Free. It has no renewal clause — $0.00 does not renew at anything worth saying.

The renewal clause — two forms, and only two

renewalPrice.total is the charge for the same period again, not a yearly rate. So the suffix depends on the term:

TermThe line reads
N = 1- **{displayName}** — 1 year — {finalPrice} (renews at {renewalPrice}/yr)
N > 1- **{displayName}** — {N} years — {finalPrice} (renews at {renewalPrice} every {N} years)

Never write /yr on a multi-year term. For a 3-year .biz the renewal figure is $107.50 — the next three-year charge. "renews at $107.50/yr" overstates it threefold. This is the single most likely way to get this section wrong, and it is wrong in the direction that scares a user off a purchase they were about to complete.

Where the two figures come from

Both are the ones §P3 already fetched for the chosen cyclefinalPrice.total.formattedAmount and renewalPrice.total.formattedAmount from the pricingDetails[] row the user picked. Reuse them:

  • Never re-request. The offering call already ran; calling it again is a second chance to get a different answer.
  • Never recompute. §P3's ban on arithmetic holds here — no dividing a 3-year renewal by three, no multiplying a 1-year figure up.
  • Never estimate. If §P3 rendered a blank renewal cell for the chosen row, the summary line drops the clause entirely and shows the price alone. A blank stays blank; it does not get filled in at checkout time.

The privacy addon line

The addon carries renewalPrice too — verified live against the addon product type (b3d86a1d-9db3-4f69-bd54-c132808856b1), same pricingDetails[] shape as the domain, one row per cycle. So the addon line gets the same treatment as the domain line: same two term forms, same prohibition on /yr for a multi-year term, same reuse rule (§P6 already read the row for the chosen cycle).

One observed difference, and it is not a reason to change the shape: on all three addon products the renewal figure equals the first-term figure — Privacy + DNSSEC is $12.90 now and $12.90 at renewal, Privacy only $9.90 and $9.90. Unlike the domain, the addon has no introductory discount. Print the clause anyway. "$12.90 (renews at $12.90/yr)" is the useful answer to "does this one jump too?", and suppressing it whenever the numbers match would make its absence look like missing data rather than a flat price.

Why the summary carries a renewal at all. §P3's table already showed it, and this is the last screen before payment — the one the user actually reads. A summary that shows only "$7.90" on a domain that renews at $35.90 is accurate and still leaves the user surprised in twelve months. The number is already in hand; the only work here is printing it with the right period attached.

Every figure in this section is an observation about shape, not a price. $107.50, $12.90, $9.90, $7.90, $35.90 — all of them are here to show which period a number covers and how far a renewal can step. None of them is ever printed to a user. §P3's rule is the whole rule: a figure that did not arrive in an API response during this conversation is a fabrication, and that applies to numbers read out of this document exactly as it applies to numbers read out of your own knowledge.

The user's only remaining step is payment; say nothing more.

Terminal state. Stop here.


P10. Forbidden Actions

Never:

  • Promise "free for the first year" without confirming coupon eligibility (§P2.1).
  • Present the Free-tier choice without the connect constraint. "Want a bundle link?" on its own is an upsell; the same question with "connecting a domain requires one" in front of it is a decision. US-19 asks for the second. Both §P2.3 variants carry the clause, including the just-logged-in one.
  • State a renewal figure per year for a multi-year term. renewalPrice.total is the charge for the same period again — /yr belongs on a 1-year term and nowhere else (§P3, §P6, §P9).
  • Mention a sale that getPremiumSale did not report.
  • Skip the contact confirmation in §P4.1 because the details "look right".
  • Continue to §P3 after the user accepted a bundle link — that is the end of the flow.
  • Put msid on a standalone checkout link, or leave it off when a Premium site is attached.
  • Re-check availability for a domain that came from the suggest endpoint.
  • Narrate cart operations, contact saving, or the premium re-check.

Always:

  • Render exactly the cycles the offering call returned.
  • Carry the currency note in the same message as any price the user sees — §P3, §P6 and §P9. Fixed wording, and never a currency name or a conversion (§R10).
  • Show what the domain renews at wherever its price appears — the period table (§P3) and the pre-checkout summary (§P9). Same two figures, fetched once.
  • Reuse the same wsess across the intent save and both cart line items.
  • Keep siteId from §P1 through §P9.

Part C — Connect Path

Entry preconditions — you arrive here from Part A with:

  1. A single normalized domain, and
  2. Confirmation it is registered (availability.available: false) — or that it is a subdomain, which is not separately registrable and so has no availability answer at all (§R1.1, §A3.1), and
  3. An ownership state, which is one of:
Ownership stateSet byConsequence here
ConfirmedThe account lookup found it — §A4b-BThe domain is theirs. Use the unconditional copy, and the connection can be performed (§C3).
Confirmed via rootThe subdomain's root domain is in the account — §A3.1bThe subdomain is theirs. Use the unconditional copy naming the root, but never bind — §R4.4's first condition asks for a match on the domain being connected (§C3).
AssertedThe user said so, or the intent was CONNECT — §A4b-COwnership is an inference. Keep the "If it's yours" hedge, and never bind (§C3).

If you arrive without one, ownership is asserted — the cautious reading. Never upgrade an asserted state to confirmed on the strength of the user repeating themselves; only the lookup in §R4.3 confirms.

Order matters: availability is checked before any site work — that already happened in §A4. Do not resolve a site first and then check the domain. If you got here without a confirmed-taken domain, go back to §A4.

If the domain turns out to be available, the user does not own it — that is §A4a, not this part.

A subdomain is the one exception to both paragraphs. No availability call was made and none should be; §A3.1 resolved ownership from the account instead. Do not send a subdomain back to §A4 for a check that has no answer.

Terminal states — this path ends in exactly one of:

Terminal stateReached when
Already connectedThe domain is already on the requested site in the role wanted (§C0a)
Connected — you did itA bind succeeded (§C3.4)
Connect linkA site is resolved, it is Premium, and no bind is on offer or the offer was declined (§C3)
Connect link + upgrade blockA site is resolved and it is Free (§C4)
Sign-upThe user has no Wix site and wants to create one (§C5)
Error fallbackTwo failed attempts — §R8

Read Part R before any call. The bind in particular is governed by §R4.4, including the four-part gate that decides whether one may be attempted at all.

⚠️ The bind in §C3.4 is this skill's only write to a user's live site, and because it re-assigns, a single POST can change two live sites (§C0c). One explicit yes sits in front of every POST, a second and named yes in front of anything that displaces a live primary domain, and every offer to move a domain names the site it comes off. There is no path through this part that connects or moves a domain without the user saying so.

Covers US-17, US-33 – US-36, US-40 – US-46.


C0. Already Connected — Stop Before You Start

If the ownership lookup (§R4.3) matched under assigned — at sites[].primary.domainName or sites[].redirects[].domainName — the domain is already on one of the user's sites. Read siteName and siteId from the entry that matched, and note how it matched: as the site's primary, or as one of its redirects[].

Three cases, and they end differently.

C0a — On the site the user asked about, in the role they want (US-40)

The job is already done. Do not resolve a site, do not check a plan, do not send a connect link, do not bind. Say it and stop:

{displayName} is already connected to {siteName}.

If the match was a redirect and a redirect is what they asked for:

{displayName} is yours — it's currently forwarding to {siteName}.

Terminal state. Stop here.

C0b — On that site, but in the other role (US-45)

The domain is theirs and it is already on the right site — only its role is wrong. Nothing has to come off anything, so this one can be acted on. The assigned match makes ownership confirmed.

Currently a redirect, and the user wants it to be the site's address:

{displayName} is already on {siteName} — right now it forwards there rather than being the site's primary domain. Want to make it the primary domain instead?

A yes here is not authorization for the POST. Continue to §C2 (the plan check) and §C3.1 (what is on the site), then §C3.3's named confirmation, then §C3.4.

The mirror case — currently the primary, and the user wants it demoted to a redirect — runs the same route with bindType: REDIRECT. One thing to check first: a redirect needs somewhere to point. If §C3.1 shows this domain is the site's only domain, there is nothing to redirect to. Say so and stop:

{displayName} is {siteName}'s only domain, so there's nothing for it to redirect to.

C0c — On a different site — a move (US-46)

The domain is theirs, and it is in use somewhere else. A bind re-assigns it — binding it to the requested site moves it off the site it is on now. No unbind call is needed and none exists; the move is the bind.

So this is not a hand-off branch. It is the branch that changes two live sites with one POST, and it is gated harder than anything else in this part: the domain stops doing whatever it was doing on the site it leaves, and that site may be losing its primary domain.

Ownership is confirmed — the assigned match proves it. Note two things from the matching entry before going on:

NoteFrom
{current siteName} — the site it is on nowsites[].site.siteName on the matching entry
{role phrase}the primary domain for, when it matched primary; forwarding to, when it matched redirects[]which field matched

The requested site is known

The user named a site, or one is in context. Continue: §C1 to resolve it, §C2 for its plan, §C3.1 for what is on it, then §C3.2d — the move's own offer form — and §C3.3 when the move also displaces a primary domain on the target. §C3.2d and §C3.3 are both mandatory for a move. A move never reaches §C3.4 on fewer than one explicit yes, and never on a yes to a question that did not name {current siteName}.

If §C2 says the requested site is Free, there is no move: §C4, link plus upgrade block, no offer, no POST.

The requested site is not known

The user said "my site" and has more than one. They may well have meant the site the domain is already on — in which case the answer is §C0a and nothing needs doing at all. So report the current state and ask the question that actually branches:

{displayName} is currently {role phrase} {current siteName}. Did you want it on a different site?

  • Names a different site → resolve it (§C1) and continue as above.
  • No, that's the one → §C0a's copy. Terminal.

⚠️ Never say what happens to {current siteName} after the move. Whether it falls back to a wix.com address, whether another of its domains is promoted, whether anything about it breaks — none of that comes from any call this skill makes. Name what the domain stops doing; stop there.

Everything below assumes §C0a did not fire. §A4b-A normally catches this before you get here; §C0 exists so an arrival that skipped it still lands correctly.


C1. Resolve the Site

Connecting a domain requires a Wix site. Apply §R3:

CaseAction
AsiteId already in context, or the user named a site → use it. Do not fetch list of sites.
BLogged in, no siteId → fetch list of sites. One site → use it silently. 2 – 8 → list them all, numbered, in the message that asks. More than 8 → name the total, show five, invite a name (§R3 Case B). Never a bare count.
B, no sites→ §C5
CNot logged in → "To connect a domain you'll need a Wix site — [Log in or create a Wix account]". End the turn until they log in, then go to Case B.
ROwnership is confirmed via root and the root's assigned match named a site → that site is a candidate, not a resolution. Offer it and wait — below.

Do all of this silently, Case R excepted. The user should see one message at the end of this path, not a play-by-play.

After a Case C login, run the ownership check (§R4.3) before continuing — it could not run while they were logged out. A match changes the answer: assigned sends you to §C0, unassigned upgrades ownership to confirmed, which is what opens the door to §C3.1 – §C3.4.

Case R — the candidate site came from the root domain (US-48)

A subdomain arrives here with ownership confirmed via root. If that root match came back under assigned, the response named the site the root is on (§R4.3) — the only site the account can suggest, and no evidence at all about where the user wants the subdomain. Two different questions; the account answered the first one.

Case A wins over this one. If a siteId is already in context, or the user named a site, the site is not in doubt and there is nothing to ask — use it and say nothing. Case R is for the one situation where the root's match is the only thing pointing at a site.

So ask, in one message, and put no link in it:

{root displayName} — the root domain — is already on {root siteName}. Want {displayName} on that site too?

The user saysDo
yes / "same site"That is the resolved site. Continue to §C2.
names a different siteResolve that name as Case A or Case B, then continue.
no, or is unsure whichCase B: fetch list of sites and ask which one.

Do not send the connect link with the question. Every connect URL carries a siteId (§R6), so a link in that message answers the question on the user's behalf and then asks it — the failure this case exists to prevent. The link goes out with §C3's opening, once a site is chosen.

If the root matched unassigned instead, no site was named — there is nothing to offer and no question to ask. Go to Case A or Case B as usual.


C2. Check the Site's Plan

Copy

Read payload.premiumState. allowedDomain = premiumState !== "FREE".

  • allowedDomain: true → §C3
  • allowedDomain: false → §C4

Run this together with §C3.1's inventory call — two calls, one silent step, no user-visible gap between them. If the site turns out to be Free, discard the inventory and go to §C4; the wasted read costs nothing and saves a round trip in the common case.

⚠️ The premium field on the availability response is domain pricing, not site Premium status. It has nothing to do with this decision. Ignore it. Neither does allowedDomain on the site object inside a My Domains response — premiumStatus is the only source.


The site is Premium, so a domain can go on it. Two routes exist, and they are not alternatives you pick between — the offer to do it and the dashboard link go out together, in the same message.

The two routes answer the two things connect can mean (§A2). The link brings a domain into the Wix account — connect it to Wix, add it to Wix — and is the only route available for a domain the account does not already hold. The bind assigns a domain the account already holds to a particular site — connect it to my site, assign it, bind it. Sending both at once is what makes the message answer either request without asking the user which they meant.

Which routes are available is decided by the ownership state, not by taste:

State you arrived withWhat this section does
Confirmed — an unassigned exact match, or an assigned match (§C0b same site, §C0c another site)Offer to connect it and give the link. §C3.1 → §C3.4.
Confirmed via root — a subdomain whose root domain is in the accountThe link is the whole answer, with the unconditional opening. No bind, no primary/redirect question.
Asserted — the user said so, the lookup found nothing, or it could not runThe link is the whole answer. No bind, no primary/redirect question.

When no bind is on offer, this section is one message and the ownership state picks the opening:

Ownership confirmed:

{displayName} is yours and isn't connected to a site yet — Connect it to {site name}

Ownership confirmed via root (a subdomain — §A3.1b, US-48):

{displayName} sits under {root displayName}, which is in your Wix account — Connect it to {site name}

Ownership asserted:

{displayName} is registered. If it's yours — Connect it to {site name}

The link is identical in all three. Only the sentence in front of it changes, and it changes because one of them is a fact, one is a fact about a different domain that settles this one, and the last is a guess. Do not blend them — "is yours. If it's yours…" is the failure this split exists to prevent.

On the root variant, q= carries the subdomain, never the root — the root is what proved ownership, the subdomain is what gets connected. Both names in the sentence go through §R2 for their display form.

The link is the same one every offer below carries:

  • q= takes the full domain, never the truncated display form.
  • The visible label is Connect it to {site name}; {displayName} is the domain's display form (§R2). Every domain shown to the user goes through §R2 — including the site's current primary domain.
  • No referralInfo parameter — see §R6.

Add nothing after the link. Terminal state. Stop here.

Ownership confirmed → do not stop. Continue to §C3.1.

Ownership confirmed via root → stop here, exactly like asserted. The wording is unconditional but the bind gate is not met, so §C3.1 – §C3.4 do not run.

C3.1 What is already on this site? (silent)

Before offering anything, find out what the site already has. One call, run with §C2:

Copy

Read exactly three things (§R4.4): sites[0].primary.domainName, sites[0].redirects[].domainName, sites[0].site.siteName. Nothing else in that response is in scope.

What came backBranch
The target domain is this site's primary, or in its redirects[]It is already on this site → §C0a (same role) or §C0b (other role). Do not offer a fresh connect.
sites[] is empty — the site has no domains at all§C3.2a
primary.domainName is absent (redirects only, no primary)§C3.2a — there is no primary domain to redirect to, so the two-way question is unanswerable.
primary.domainName is present§C3.2b
The call fails, and its silent retry also failsNo bind. Fall back to §C3's link-only confirmed opening. The inventory is what makes the question askable; without it, do not guess a primary domain.

The target domain turning up here means the searchTerm lookup (§R4.3) missed it — most often because the user was logged out at the time. Trust this call and route to §C0.

On a move (§C0c) the branch conditions are unchanged — what changes is the copy: §C3.2d replaces §C3.2a and §C3.2b, and which of its two forms applies still turns on whether the target site has a primary domain.

C3.2 The offer — one message, both routes

Four copy forms. Pick by what §C3.1 found, by whether the domain is coming off another site (§C0c), and by whether the user has already said which role they want.

A move (§C0c) always uses §C3.2d, whatever else applies — it is the only form that names the site the domain is leaving, and a move may not be offered without naming it.

C3.2a — the site has no primary domain yet

Nothing to redirect to, so there is no choice to present. It is still a write, so it still needs one yes:

{siteName} doesn't have a primary domain yet. Want me to make {displayName} its primary domain?

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

C3.2b — the site already has a primary domain

{siteName}'s primary domain is {current primary}. Should {displayName} become the primary domain instead, or redirect to it?

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

C3.2c — the user already said which role they want

"connect it as a redirect", "make it the main one" — the two-way question is already answered. Do not ask it again. Ask the one-way confirm instead:

{siteName}'s primary domain is {current primary}. Want {displayName} to redirect to it?

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

When the pre-stated role is PRIMARY and the site has one, §C3.3 is that confirm — go straight there and skip this form. When it is PRIMARY and the site has none, use §C3.2a.

C3.2d — the domain is coming off another site (§C0c, US-46)

The bind re-assigns, so the offer has to say what the domain stops doing. {role phrase} and {current siteName} come from §C0c.

The requested site has a primary domain:

{displayName} is currently {role phrase} {current siteName}. Moving it to {siteName} takes it off {current siteName} — should it become {siteName}'s primary domain, or redirect to {current primary}?

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

The requested site has no primary domain:

{displayName} is currently {role phrase} {current siteName}. Want me to move it to {siteName} and make it the primary domain there? That takes it off {current siteName}.

Or do it yourself — [Connect it to {siteName}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

Both forms name the site being left, in the same message as the offer, before any yes is possible. That is the point of this form and it is not optional. A pre-stated role (§C3.2c) does not let you skip it — collapse the two-way question if the role is already settled, but keep the sentence that names {current siteName}.

Reading the answer

The user saysDo
primary / "make it the main one" / "instead"bindType: PRIMARY → §C3.3 if the site has a primary, else §C3.4
redirect / forward / point it at the other onebindType: REDIRECT → §C3.4
yes (to §C3.2a, §C3.2c or §C3.2d)The role that question named → §C3.3 if it displaces a primary, else §C3.4
no / "I'll do it myself" / changes the subjectNo POST. The link is already in front of them. Stop.
anything ambiguousAsk the same question once more. Never guess a bind type — one of the two options overwrites the site's live address.

Silence is not a yes. An unanswered offer is a terminal state, not a pending instruction.

C3.3 Replacing a live primary domain (US-44)

Fires when bindType is PRIMARY and §C3.1 found a primary.domainName on the target site. It is not optional and it cannot be folded into §C3.2 — the point of it is that the domain being replaced is named before anything moves:

{siteName}'s primary domain is {current primary} right now. Making {displayName} the primary domain will send visitors to {displayName} instead. Go ahead?

On a move (§C0c), the domain being replaced is not the only casualty — say both sides in one question, and do not split it into two:

{siteName}'s primary domain is {current primary} right now. Making {displayName} the primary domain will take it off {current siteName} and send {siteName}'s visitors to {displayName} instead. Go ahead?

Wait for a yes. No yes, no POST.

⚠️ {current primary} goes through §R2 like every other domain the user sees, so a long one arrives truncated — maximz-maxmind3.com is shown as maximz...mind3.com. That is the rule as written, and it is followed here. It is also the one place where the rule works against the copy: this warning exists so the user recognises the domain being replaced. If §R2's threshold ever proves too aggressive for this line, this is the line to revisit — do not fix it by inventing a local exemption.

If §C3.2 was skipped — the user pre-stated PRIMARY, or you came from §C0b — this is the first message of the offer, so carry the do-it-yourself line under it:

If §C3.2 already went out, the link is in the thread. Do not repeat it.

A no ends the bind attempt. Do not re-ask, do not counter-offer the redirect, do not explain. Point at the link once and stop.

C3.4 Do it (US-42)

Copy

{domain} appears twice — in the path and in the body — and both are the full normalized domain (§R1), never displayName. bindType is PRIMARY or REDIRECT, whichever §C3.2 / §C3.3 settled. Send nothing else in the body.

Treat any 2xx as success and read no fields out of the response. Its shape has never been observed — see §R4.4. A field you have not seen is not data.

Success, one line, nothing after it:

Done — {displayName} is now the primary domain for {siteName}.

Done — {displayName} now redirects to {current primary}.

On a move, the same line says where it came off — the user changed two sites and should see both named once:

Done — {displayName} is now the primary domain for {siteName}, and it's off {current siteName}.

Done — {displayName} now redirects to {current primary}, and it's off {current siteName}.

Still one sentence. Nothing about what {current siteName} does now — that is not known (§C0c).

Say nothing about timing, propagation, SSL, certificates or DNS. None of it is known here and all of it is forbidden (§C7). A successful bind produces one sentence.

Failure → silent retry (§R8). If the retry also fails, fall back to the link without narrating the failure — no "that didn't work", no error, no apology for the machinery:

That is a terminal state. Do not retry a third time, and do not offer the bind again in the same conversation unless the user asks.

C3.5 The user asks you to do the connection

Expect this — "yes so connect it", "connect it from here", "why can't you do it?".

First check whether an offer is already on the table. If §C3.2 or §C3.3 has gone out, this is the answer to it — read it as such (§C3.2's answer table) and act. Do not explain, do not re-offer, do not treat a yes as a new question.

If no bind is available — ownership asserted, or a Free site — re-offer the link once and stop:

Connecting happens in your Wix dashboard — the link opens it with {displayName} and {site name} already filled in, so you just follow the steps there.

[Connect it to {site name}](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bconnect%20URL%7D*original::{connect URL})

If the user asks again, re-send the link with one short line — "That link is the way in — it's all set up for you." Do not build a new explanation each time, and do not explain why you cannot do this one when you have done others.

⛔ Never explain the mechanics. No DNS, nameservers, A records, CNAME, TXT, propagation, registrar access, "ownership verification", or "pointing vs nameservers". That is exactly the internal detail §R9 forbids, and it turns a one-line handoff into a support conversation the user did not ask for. This holds just as hard after a successful bind — a domain now being a site's primary domain is not an opening to describe what happens next in the network.

Equally, never say what you can't do — no "I have no access to your registrar", no "that's not something I can run", no listing your own limitations. Point at the link and stop.

If the user is logged in already, do not suggest logging in — the link opens their dashboard signed in.


A Free-tier site still gets the connect link — the user should see where the domain would go — but connecting is a Premium feature, so the upgrade block follows it in the same message.

No bind happens here, ever. Not the POST, not the offer, not the primary-or-redirect question — the gate in §R4.4 fails on a Free site and there is nothing to ask about. The inventory §C3.1 may have fetched is discarded unread.

The opening line splits on ownership state exactly as in §C3; the upgrade block below it is identical either way.

Ownership confirmed:

{displayName} is yours and isn't connected to a site yet — Connect it to {site name}

Upgrade {site name} with a Premium plan to connect your domain

Connecting a domain is a Premium feature. Upgrade now to let visitors reach you at a custom web address and enjoy Premium benefits.

[Upgrade →](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bupgrade%20URL%7D*original::{upgrade URL})

Ownership asserted:

{displayName} is registered. If it's yours — Connect it to {site name}

Upgrade {site name} with a Premium plan to connect your domain

Connecting a domain is a Premium feature. Upgrade now to let visitors reach you at a custom web address and enjoy Premium benefits.

[Upgrade →](fallback::https://github.com/wix/skills/blob/da14ae855651558145fd91cb95560d78e4bc9ebb/skills/wix-manage/references/domains/%7Bupgrade%20URL%7D*original::{upgrade URL})

The upgrade block copy is fixed. Do not reword it, do not add a benefits list, do not explain what Premium includes, and do not promise to connect the domain once they upgrade.

If the user does upgrade mid-conversation, re-run §C2. A site that now reads Premium goes to §C3 like any other — the offer becomes available at that point, not before.

Which upgrade URL

EditorURL
Studio (US-35)https://manage.wix.com/premium-pricing/studio/select-plan?siteGuid={siteId}
Classic / sunrise (US-36)https://manage.wix.com/premium-pricing/sunrise/select-plan?siteGuid={siteId}

Detect the editor: the dashboard URL contains /studio/, or the site context exposes editorType: "studio"studio. Otherwise → sunrise. When uncertain, default to sunrise.

Terminal state. Stop here.


C5. No Wix Site (US-17)

The user is logged in but list of sites returned nothing. Connecting is impossible without a site, so say so plainly and offer the way out:

Connecting a domain requires a Wix site. Want to create one?

  • Yes → show the sign-up entry point. In a channel with a widget runtime, that is the sign-up widget; in a plain-markdown channel, link to https://www.wix.com/. Terminal state. Stop here — do not continue into any other flow afterwards.
  • No → offer the alternative once: "No problem. Would you like to look for a domain to purchase instead?" If yes → §A5. If no, end.

Do not pitch Premium plans here — there is no site to upgrade yet.


C6. Domain Not Registered After All

If a re-check ever shows the domain is available, the user does not own it. Say:

{displayName} isn't registered yet — did you mean you'd like to purchase it?

  • Yes → Now go to §P1 and follow it.
  • No → "Do you own a different domain you'd like to connect?" → back to §A4 with the new domain.

C7. Forbidden Actions

Never:

  • Resolve a site before the availability check.
  • Fetch list of sites when a siteId is already in context — including when the site was already named by the ownership lookup (§R3, Shortcut).
  • Send a connect link for a domain that is already connected in the role asked for. Check §C0 first.
  • Bind a subdomain on the strength of its root domain. Confirmed via root earns the unconditional wording and nothing else; §R4.4's first condition wants a match on the domain being connected. The link is the whole answer there.
  • Adopt the root domain's site as the subdomain's. A root match under assigned names the site the root is on. It is the only site the account can suggest and it is still a guess about where the subdomain belongs — §C1's Case R offers it and waits for a yes. Since every connect URL carries a siteId, sending the link first decides for the user and presents it as an answer. "I used that site rather than asking" is not a defence; it is the bug.
  • Blend the root sentence with the hedge. "sits under {root displayName}, which is in your Wix account. If it's yours —" states a fact and then doubts it. The three openings above are three, not ingredients.
  • Bind without all four conditions in §R4.4. Ownership merely asserted, no siteId, a Free site, or no affirmative answer — any one of them makes the link the whole answer.
  • Bind on the strength of ownership the user asserted. An externally-registered domain the lookup never saw is not yours to write to a live site.
  • Move a domain without naming the site it comes off. A bind re-assigns, so §C0c's move changes two live sites with one POST. §C3.2d names the site being left, in the offer, before any yes is possible — and §C3.3 names it again when a primary domain is also being replaced. An offer that says only where the domain is going is not a valid offer for a move.
  • Say what happens to the site the domain leaves. Whether it falls back to a wix.com address, whether one of its redirects gets promoted, whether anything breaks — no call this skill makes answers that. Name what the domain stops doing and stop.
  • Ask a question whose yes and no produce the same reply. "Want to move it to {requested site}?" followed by a bare link is the specific failure: it offers to act and withdraws it a turn later. If a move is genuinely on offer, §C3.2d asks for it and §C3.4 performs it; if it is not — a Free target site — do not raise it at all.
  • POST a bind the user did not say yes to, or infer a yes from silence, from a repeated request, or from an ambiguous answer.
  • Replace a live primary domain without §C3.3. The domain being displaced is named, and the user confirms, before anything moves.
  • Guess a bindType. One of the two overwrites the site's address. Ambiguity is re-asked, not resolved.
  • Read a field out of the bind response. Its shape is unverified; a 2xx is the entire signal.
  • Say "main address", "main domain", "main URL" or "root domain" for primary domain — see §R9. The user may say "main one"; your reply says "primary domain".
  • Promise timing, propagation, SSL or "up to 48 hours" after a bind. None of it is known.
  • Narrate a bind failure. Silent retry, then the link (§C3.4).
  • Say "If it's yours" when the account lookup has confirmed it is theirs — or drop the hedge when it has not. The two openings in §C3 are not interchangeable.
  • Ask "do you already own this domain?". Either the lookup answered it or the hedge covers it.
  • Show the upgrade block to a Premium site, or omit the connect link for a Free site — Free-tier users get both.
  • Ask the primary-or-redirect question on a Free site, or anywhere else no bind can follow it.
  • Use availability.premium to decide Premium status.
  • Reword the upgrade block, or explain Premium's feature set.
  • Add text after the connect link, the upgrade block or the success line.
  • Offer to purchase a domain the user has just said they own.
  • Explain DNS, nameservers, A/CNAME/TXT records, propagation or registrar access — ever, to anyone, however directly asked, before or after a successful bind. See §C3.5.
  • Narrate your own limitations ("I can't do that from here", "I have no access to…"). Re-send the link instead.

Always:

  • Use the full domain in q=, in the bind path and in the bind body; the site's display name in the link label; displayName (§R2) for every domain the user sees, including the current primary.
  • Pick the §C3 / §C4 opening from the ownership state you arrived with, defaulting to asserted.
  • Put the do-it-yourself link in the same message as the offer.
  • Default to sunrise when the editor type is unclear.
  • Keep the whole path to a single user-visible message where possible — the offer is one message, the result is one line.

Part R — Reference

Read this part before making any API call. It is the single source of truth for endpoints, product IDs, URL templates, site resolution and error handling. Parts A, P and C all defer to it — where they disagree with this part, this part wins.

Covers US-13, US-14, US-15, US-16, US-37, US-38, US-39.

§R4.3 (domain ownership) is the mechanism behind US-40 and US-41, and it is what scopes US-09 to domains the lookup does not find. §R4.4 (bind) is the mechanism behind US-42 – US-45. See §C3.

⚠️ §R4.4 is the only write to a user's live site anywhere in this skill. Its gate is not advice.


R1. Domain Normalization

Apply before any API call, every time a domain is read from the user:

  • Strip http:// and https://
  • Strip www.
  • Strip any trailing path, query string or slash (example.com/shopexample.com)
  • Lowercase
  • If there is no TLD, add .com (exampleexample.com)

The normalized value is {domain} everywhere below. Always use the full domain in URLs and API calls — never the truncated display form.

R1.1 Root Domain and Subdomains (US-48, US-49, US-50)

Some hosts a user names are subdomainsshop.maximz.fr sits under maximz.fr. That changes who can be shown to own it, so settle it here, during normalization, before any call.

Extract the TLD greedily from the right, exactly as §R7 does — .co.uk, never .uk. What remains is the name part:

Normalized inputTLDName partVerdict
maximz.fr.frmaximzroot domain
mybrand.co.uk.co.ukmybrandroot domain
shop.maximz.fr.frshop.maximzsubdomain — root is maximz.fr
shop.mybrand.co.uk.co.ukshop.mybrandsubdomain — root is mybrand.co.uk

One label in the name part is a root domain. More than one is a subdomain, and its root domain is the last label of the name part plus the TLD.

A multi-label TLD is not a subdomain. mybrand.co.uk has three labels and no subdomain. Greedy extraction is exactly what stops .uk being read as the TLD and co.uk being offered as a domain to connect — nobody owns co.uk.

On an unfamiliar suffix, treat the host as a root domain. §R7's list covers the multi-label suffixes this skill has met and is not exhaustive — .co.il and .com.mx are real and missing from it. Guessing subdomain wrongly produces an offer to connect something unregistrable; guessing root domain wrongly just falls back to the ordinary flow. Take the fallback.

Note that www. is already gone by this point — the strip rule above removes it, so www.maximz.fr is the root domain maximz.fr and never a subdomain.


R2. Domain Display Truncation

Only the visible label is ever truncated. Two values exist for every domain:

ValueUse
domainNameFull normalized domain — URLs, API calls, cart metadata
displayNameWhat the user sees in link text and summaries

Rule: if the full domain is 20 characters or fewer, displayName = domainName. If it is longer than 20 characters:

Copy
Full domainLengthdisplayName
short.com9short.com
myamazingbusiness.com21myamaz...iness.com
verylongdomainname.com22verylo...nname.com

R3. Site Resolution

Both paths need to know which Wix site (siteId, also called msid) is in play. The rules are the same; when they run differs:

  • Purchase path — a site is optional. Resolve only after the domain is chosen. See §P1.
  • Connect path — a site is required. Resolve only after the availability check. See §C1.

Shortcut: if the ownership check (§R4.3) came back with an assigned match on the domain being connected, the site is already named in that response (sites[].site.siteName / .siteId). Use it. Nothing below needs to run — in particular, do not fetch list of sites to re-discover a site you have just been handed.

A match on a subdomain's root domain is not that match. It names the site the root is on, which is a guess about where the subdomain belongs — the only site the account can suggest, and still the user's to choose. Offer it and wait: §C1, Case R. This is the line §R4.4's condition 1 already draws — a root match settles ownership and nothing that gets written.

Case A — siteId already in context (US-13)

The system prompt, environment or dashboard context already provides a siteId / msid.

→ Use it directly. Do NOT fetch list of sites. Do not ask the user to pick a site.

The user naming a site is not the same thing. If they say "my site is called My Bistro" but no siteId is in context, you still need to fetch list of sites to turn that name into an ID — go to Case B. What their answer buys you is skipping the "which site?" question, not the lookup. Match the name against the returned sites; if nothing matches, list what came back and ask.

A roster in context is not a resolved siteId either. The host may preload part of the account's site list — ten of ninety-three, say — into the system prompt or site context. That is not Case A. It names no site for this domain, it may not even contain the right one, and it hands you no siteId for the task. Go to Case B and fetch list of sites. Every prohibition on that call is about a siteId you already hold, never about a list you happened to be shown.

Case B — user is logged in, no siteId in context

→ Fetch list of sites.

ResultAction
Exactly one site (US-14)Use it directly, no question asked. Name it in your next message so the user can spot a mistake.
2 – 8 sites (US-15)List them all, numbered, in the same message as the question: "You have a few Wix sites — which one should this domain be connected to?" ("a couple" when there are exactly two.) Wait for the pick.
More than 8Still a list, never a count — name the total, show five, invite a name. Copy below. Wait for the pick.
No sitesPurchase path → continue standalone. Connect path → US-17 terminal state, see §C5.

More than eight sites. A numbered wall of ninety-three is unusable, and a bare count is worse. Name the total, show five, and leave the door open:

You have 93 Wix sites. Which one should {displayName} go on?

  1. {site name}
  2. {site name}
  3. {site name}
  4. {site name}
  5. {site name}

Or tell me the name and I'll find it.

Show the five most recently updated if the response gives you that; otherwise the first five it returned. A name in reply is matched against the whole result you already have — do not fetch list of sites a second time to look it up.

Never announce the count and stop. "You have 93 sites — would you like me to list them?" asks permission for the step you were already told to take. The user has asked for their domain on a site; the list is what moves that forward and a count moves nothing. It costs a turn and answers nothing.

Case C — user is not logged in (US-16)

Do not ask a yes/no question about sites — the user cannot answer it usefully. Show the optional inline prompt instead, verbatim:

If you'd like to connect this domain to a Wix site — [Log in or create a Wix account]

  • User logs in → go to Case B (fetch list of sites).
  • User declines ("No, I'll just buy it for now") → standalone purchase, no siteId, no premium pitch, no voucher check. Reply "No problem." and continue.

The destination behind [Log in or create a Wix account] is supplied by the host channel's sign-up/login affordance. In a channel with no widget runtime, link to https://www.wix.com/.

Case D — user is logged in and no site was mentioned

Purchase path only. Ask once, verbatim:

Would you like to connect this domain to one of your Wix sites?

  • Yes → Case A or B.
  • No → standalone purchase, no siteId. Reply "No problem." and continue.

Once a siteId is resolved, remember it for the rest of the conversation and reuse it in the premium check, the bundle link and the checkout link.


R4. API Reference

R4.1 Public — no auth

These are open endpoints. Send a plain GET with query parameters: no headers, no tokens, no scopes. If you get 403 / access_denied, you added auth that does not belong — remove it and retry.

Do not use the GetSuggestedDomains tool. Always use the v2 endpoint below.

Check domain availability

Copy
Copy
FieldMeaning
availability.available: trueNot registered — buyable
availability.available: falseRegistered — taken
availability.premium⚠️ Ignore completely. This is domain pricing tier, not Wix site Premium status. Site Premium comes only from premiumStatus (§R4.2).

Unsupported TLD is not a field on the success body — it is an HTTP 400 error body:

Copy

Detect it at details.applicationError.code === "DOMAINS_UNSUPPORTED_TLD". Do not look for availability.available on this response — the availability object is absent.

Suggest domains

Copy

Accepts free text — business descriptions, keywords and brand concepts, not just domain names.

ParameterNotes
queryKeywords, business idea or brand concept. When alternatives for a taken/unsupported domain: use the SLD only (for mybusiness.com, query mybusiness).
paging.limitAlways 3 on the first page. See §A5.
paging.cursorOpaque cursor for the next page — see below.
tldsOptional TLD filter, repeatable, no leading dots (&tlds=com&tlds=net).
Copy

Paging is cursor-based. pagingMetadata.hasNext tells you whether more exist; it does not fetch them. To get the next page, repeat the same query and paging.limit and add paging.cursor=<pagingMetadata.cursors.next>. Never re-issue the same request without the cursor — you will get the first page again.

Every returned suggestion is already available. Never re-check availability for a suggestion. Never show a "premium" column or flag premium suggestions.

R4.2 Authenticated

Use CallWixSiteAPI (with siteId) when a site is resolved, otherwise ManageWixSite. Both carry Wix session auth automatically — do not add headers.

PurposeCall
List the user's sitesfetch list of sites
Site Premium statusGET https://manage.wix.com/_api/premium-store/plans/premiumStatus?metaSiteId={siteId}
Domain cycles + pricingPOST https://manage.wix.com/_api/premium-purchase-platform-serverless/v1/offering/72af0602-1321-4897-8299-f507480b2bb8
Body: { "purchaseContext": { "params": { "tld": ".{TLD}" } } }
Privacy addon pricingSame offering endpoint with the addon product type id b3d86a1d-9db3-4f69-bd54-c132808856b1
TLD coupon eligibilitycom.wixpress.premium.domain.tlds.DomainTld/ListTlds
Body: { "filter": { "tlds": ["{TLD_WITHOUT_DOT}"] } }
Active Premium salegetPremiumSale context call → wix.premium.store.v1.sales/GetSale
Existing contactsGET https://manage.wix.com/v1/domain-registration-intents/preview/{domain}
Save contactsPOST https://manage.wix.com/v1/domain-registration-intents/upsert
Cancel active cartPOST https://manage.wix.com/_api/premium-cart/v1/carts/active/cancel · Body {}
Get fresh cartGET https://manage.wix.com/_api/premium-cart/v1/carts/active
Add items to cartPATCH https://manage.wix.com/_api/premium-cart/v1/carts/active/add-items
Does this domain belong to the userSee §R4.3 below — two calls, run together
What domains are already on a siteGET https://manage.wix.com/_api/my-domains/v1/domains/assigned?filter.msid={siteId} — see §R4.4
Connect a domain to a sitePOST https://manage.wix.com/_api/my-domains/v1/domains/{domain}/bind — see §R4.4. This is a write. It is gated.

Premium status: read payload.premiumState. allowedDomain = premiumState !== "FREE". allowedDomain: true → Premium site. allowedDomain: false → Free site.

The offering endpoint is the getDomainCycles call — the same one the production get-domain purchase flow uses. Noted for whoever next reconciles this skill against production; it changes nothing about how the call is made.

Both offering variants return the same envelopeproducts[].pricingDetails[], one entry per cycle, each carrying finalPrice and renewalPrice. Verified live for the domain type and the addon type alike. renewalPrice.total is always the charge for the same period again, never a yearly rate (see §R9).

R4.3 Domain Ownership — My Domains

Answers a question the availability check cannot: the domain is registered, but is it registered to this user? Without it, "taken by a stranger" and "sitting in your own account" look identical.

Copy

Both go through ManageWixSite — ordinary account-level Wix session auth, the same family as premiumStatus, the cart and the offering call. No account-level API key is needed. Do not add headers.

{domain} is the normalized domain (§R1) — maximz.fr. Never the truncated displayName, never the SLD alone.

Run both, together, silently, and only when available: false. An unregistered domain has no owner, so there is nothing to look up.

A subdomain is the one other entry point (§A3.1). A subdomain is not separately registrable, so no availability check runs for it and this lookup is reached directly: keyed on the subdomain first, then — only if that finds nothing — keyed on its root domain (§R1.1).

A root-domain match confirms the subdomain. The account holding maximz.fr is the account that decides what shop.maximz.fr resolves to, so there is nothing left for the user to assert. Compare exactly against whichever value you searched, the subdomain or the root, and never against the other.

Confirmed-via-root does not unlock a bind, and does not resolve a site. It settles the wording — the unconditional opening instead of the hedge — and nothing else. §R4.4's first condition still asks for an exact match on the domain being connected, and a root match is not one: the link is the whole answer there. And the site named alongside a root match is the root's site, so it is a candidate for the subdomain rather than a resolution — §C1, Case R asks the user before it reaches a link.

Response shapes

assigned — the domain is on one of the user's sites. The array is of sites, not domains:

Copy

unassigned — the domain is in the user's account but on no site:

Copy

No match on either is the empty form — {"sites": [], "isAllDataReturned": true} and {"domains": []}. Both are normal answers, not errors.

⚠️ The unassigned response has its own displayName field. It is not the skill's displayName from §R2 — it is the API's own label and carries no truncation. Compute the visible form yourself with §R2. Never render the API's displayName.

Both responses carry far more than the fields above — registrant names, street addresses, phone numbers, contract IDs. None of it is ever shown to the user or reasoned about. You need exactly two things out of this call: does it match, and what is the site called. Reading a registrant's address out of this response is the same violation as a WHOIS lookup (§A1.1).

⚠️ filter.searchTerm is a search, not a lookup

It matches on substrings. filter.searchTerm=maximz returns 35 domains — maximz.fr, maximz1.de, sub3.maximz-cor.com and 32 others. A hit is not ownership.

Always compare the returned string to {domain} exactly (both already lowercased by §R1) before concluding anything. Look in these places, in this order:

Exact match found atMeaning
sites[].primary.domainNameOwned, and it is that site's address → already connected. Site name is sites[].site.siteName on the same entry.
sites[].redirects[].domainNameOwned, and already in use — it forwards to sites[].site.siteName. Still "already connected", not free to connect.
domains[].domainName (unassigned)Owned, on no site yet → free to connect.
NowhereNot in this user's Wix account. See the caveat below — this is weaker than "someone else owns it".

⚠️ A miss does not prove the user doesn't own the domain. These endpoints see the user's Wix account, not the registry. A domain registered at an outside registrar and never connected to a Wix site appears in neither response, and its owner may be sitting right there in the conversation. (Externally-registered domains that are connected do show up — they arrive under assigned with wixRegistration: false and managementType: "POINTING".)

So a match is proof of ownership; a miss is only absence of proof. Never tell a user a domain belongs to someone else. The "no match" copy hedges ("If it's yours…") for exactly this reason, and it must keep hedging.

Read siteName and siteId from the entry whose primary or redirects[] matched — a single response can contain several sites, and the first one is not necessarily yours.

sites[].transfers appears on every entry but was empty in every response observed. Its contents are unverified — do not read fields from it. A domain found nowhere else counts as no match.

The site object also carries allowedDomain. Do not use it as the Premium check. Site Premium has exactly one source, premiumStatus (§R4.2), and two sources will eventually disagree.

The same endpoint, filtered by site — filter.msid

assigned takes a second filter. Swap the search term for a site ID and it stops answering "where is this domain?" and starts answering "what is on this site?":

Copy

Same envelope, same fields, same reading rules — one sites[] entry per site, primary, redirects[], transfers, isAllDataReturned. Verified live in both shapes:

SiteResponse
Has domains{"sites":[{"site":{…},"primary":{…},"redirects":[…],"transfers":[]}],"isAllDataReturned":true}
Has none{"sites":[],"isAllDataReturned":true}empty, not an error

The empty form is the answer "no domains on this site yet", and it is a perfectly normal one. Do not retry it, do not treat it as a failure, do not escalate.

This is the inventory call §R4.4 needs before it can ask the user anything. Everything already said about §R4.3 applies to it unchanged — including the exact-match rule (a filter.msid response is scoped to one site but its primary and redirects[] still have to be compared to {domain} exactly), and the rule that nothing but the match and the site name comes out of the response.

⛔ One lookup, one retry — never re-authenticate

subject is missing (HTTP 400) has been observed from the assigned endpoint while unassigned answered normally in the same breath. It does not mean you got the auth wrong, and §R4.1's "remove the headers and retry" rule does not apply to it — that one is about 403 on the public endpoints.

So do not go hunting for a second auth shape. Not scope: "account" in place of scope: "site", not a different siteId, not ManageWixSite after the same 400 came back from ExecuteWixAPI. Two calls, one silent retry, and this lookup is finished — apply the table below and carry on with whatever the surviving call returned.

This lookup is an enrichment, not a gate: everything downstream works without it, and §A4b-C's copy already hedges for exactly this case. Four attempts at the same question is the observed failure mode, and it buys the user nothing.

When the check cannot run

SituationDo
User is not logged inSkip both calls. There is no account to search. Continue as if no match — ownership is unknown, not disproven.
One call fails, and its silent retry (§R8) also failsTreat that endpoint as no match and use whatever the other one returned. A confirmed match from the surviving call still counts.
Both failContinue as if no match. Do not show the escalation ladder for this call — it is an enrichment, and the flow it enriches still works without it.

In both cases the fallback is the no-match branch, whose copy already hedges ("If it's yours…"). That hedge is exactly right when ownership is unknown — and exactly wrong once this call has confirmed it.

R4.4 Connect a Domain to a Site — Bind

Everything else in this part reads. This writes, and it writes to a site the user's visitors are looking at right now. Read the gate before the payload.

This is the operation behind connect it to my site, assign it to my site and bind it to my site — three ways of asking for the same thing (§A2). It is not what connect it to Wix or add it to Wix means: those ask for a domain at an outside registrar to be brought into the account, which is the connect link in §C3 and a precondition of anything here. A domain the account does not hold fails condition 1 below, so the phrasing never decides whether this call may run — the lookup in §R4.3 does.

Copy
Copy

Goes through the same manage.wix.com/_api/ session auth as premiumStatus, the cart and §R4.3 — via CallWixSiteAPI with the resolved siteId, or ManageWixSite. No headers, no account-level API key.

{domain} appears twice — once in the path, once in domainName — and both are the full normalized domain (§R1). Never the truncated displayName, never the SLD alone, never a www. form. Send no fields beyond the three above.

bindTypeMeaning in the product
PRIMARYThe domain becomes the site's primary domain — the address visitors are sent to.
REDIRECTThe domain becomes a secondary domain — it forwards visitors to the site's existing primary domain.

Those two are the whole enum. There is no third value; do not invent SECONDARY, ALIAS or POINTING.

⚠️ The response shape is unverified

This call has never been observed. Until a real response has been seen and written down here:

  • Treat any 2xx as success, and a non-2xx as a failure for §R8's silent retry.
  • Read no fields out of the body. Not a status, not a returned domain name, not an ID, not a timestamp, not an ETA. Do not branch on anything in it.

This is the same rule that stops a price being fabricated (§R9). A field you have not seen is not data, and a field name that sounds plausible is a guess with a colon after it.

The gate — all four, every time

#ConditionWhere it comes from
1Ownership is confirmed by an exact match in §R4.3 on the domain being connected — an unassigned match, or an assigned match on any of the user's sites. A subdomain confirmed only by its root domain (§R1.1) does not satisfy this§R4.3
2A siteId is resolved§R3
3The site is PremiumpremiumState !== "FREE" from premiumStatus (§R4.2), and from nothing else§R4.2
4The user has answered the offer in the affirmative — and the offer named every live thing the bind changes: the primary domain it displaces on the target site, and the site the domain comes off if it is moving§C3.2, §C3.3

If any one of them fails, there is no POST. The dashboard connect link (§R6) is the entire answer, and it is a good one — it does the same job with the user's own hands.

The failure worth naming, because it looks like a pass:

  • Ownership merely asserted. The user saying "it's mine" is not condition 1. A domain registered outside Wix and never connected to a Wix site is invisible to §R4.3, so the user may well own it — but "may well" is not the standard for writing to a live site, and such a domain needs work at its registrar that this skill is forbidden to discuss anyway.

⚠️ A bind re-assigns — one POST, two live sites

Binding a domain that is already on another of the user's sites moves it: it comes off the site it was on and lands on the new one. There is no unbind call because none is needed.

That makes condition 4 heavier than it looks. A move changes a site the user may not be thinking about — possibly taking away its primary domain — so the offer has to name that site before the user can agree to anything. §C0c and §C3.2d own that copy; this is the rule behind it.

What is not known, and must never be stated: what the site left behind does afterwards. Whether it reverts to a wix.com address, whether one of its other domains is promoted, whether anything about it breaks — no call here answers that. Name what the domain stops doing and stop.

Vocabulary is fixed

"Primary domain" and "secondary domain" are the product's own words — the dashboard, the official docs and this API all use them. Say primary domain. Never "main address", "main domain", "main URL", "root domain", or any other paraphrase. A user who says "the main one" gets an answer that says primary domain.

One exception, and it is a different concept entirely. Root domain is the correct term for the domain a subdomain sits under — maximz.fr under shop.maximz.fr (§R1.1, §A3.1). That sense is permitted. It describes a relationship between two domain names and says nothing about the role either one plays on a site, so it never stands in for primary domain. Both can be true at once without touching: a root domain may be connected as a secondary domain, and a subdomain may be a site's primary domain.

What never comes with a bind

No timing, no propagation, no "up to 48 hours", no SSL or certificates, no DNS, no nameservers. None of it is known from this call and all of it is forbidden by §R9. A successful bind is one sentence.

R5. Product IDs

ItemID
Domain product type72af0602-1321-4897-8299-f507480b2bb8
Domain product idRead products[0].productId from the offering response — never hardcode
Addon product type (all three)b3d86a1d-9db3-4f69-bd54-c132808856b1
Privacy + DNSSECf8211619-d9f6-4312-9d03-f2958bbd08aa
Privacy only22a84545-4ac0-4490-a434-45a1ebc479fb
No protectionb9d89ff0-f29b-4bfd-a3f0-6e34ae65120d

R6. URL Templates

Use these exactly. Do not invent variants, reorder into a different form, or drop parameters.

NameTemplate
Checkout — with sitehttps://manage.wix.com/cart/checkout?msid={siteId}
Checkout — standalonehttps://manage.wix.com/cart/checkout
Bundle / plan+domainhttps://manage.wix.com/premium-pricing/wix/select-plan?domainName={domain}&referralAdditionalInfo=add-domain-purchase-intent&siteGuid={siteId}&showDomain=true
Connect domainhttps://manage.wix.com/dashboard/{siteId}/add-domain/results?q={domain}&invoke=true
Upgrade — Studio editorhttps://manage.wix.com/premium-pricing/studio/select-plan?siteGuid={siteId}
Upgrade — Classic editorhttps://manage.wix.com/premium-pricing/sunrise/select-plan?siteGuid={siteId}
Fallback domain searchhttps://manage.wix.com/account/domains

Notes:

  • The bundle link is the premium-pricing/wix/select-plan form above. An older premium-domains/split-page?domainName=… form also exists — do not use it.
  • The connect link carries no referralInfo. A referralInfo=mydomains__emptyState value belongs to the My Domains empty-state entry point and does not apply to this channel. If the host channel supplies its own referral value, append it — otherwise omit it.
  • Link label for the connect URL is Connect it to {site name}; use displayName wherever the domain itself is the visible label.

Editor type (US-35, US-36)

Picks studio vs sunrise in the upgrade URL:

  • Dashboard URL contains /studio/, or the site context exposes editorType: "studio"studio
  • Otherwise → sunrise (Classic). When uncertain, default to sunrise.

R7. Free-Domain-Coupon TLDs

Used by §P2 to decide whether the "free for the first year" benefit can be promised. Authoritative source is DomainTld/ListTldscoupons_applicable: true. Use this static list only as a fallback when that call is unavailable:

.com, .com.au, .co.uk, .net, .org, .art, .at, .co.at, .be, .biz, .blog, .ca, .ch, .club, .coach, .com.br, .de, .fit, .fitness, .fr, .fun, .in, .co.in, .org.in, .firm.in, .gen.in, .ind.in, .net.in, .info, .live, .nl, .online, .pictures, .rocks, .site, .space, .shop, .store, .studio, .training, .work, .xyz, .yoga

Extract the TLD greedily from the right: site.co.uk.co.uk, not .uk.


R8. Error Handling (US-37, US-38, US-39)

Silent retry (US-37)

Any failed call: retry once, silently. Say nothing to the user, before or after. Do not narrate "let me try that again", do not mention that anything failed. If the retry succeeds, continue as if nothing happened.

Escalation ladder

StageTriggerSay (verbatim)
1Call fails, retry also failsSomething went wrong on our end. Please try again in a moment.
2The user tries again and it fails againHaving trouble loading this — try again. You can also search for a domain directly → https://manage.wix.com/account/domains

The fallback link appears at stage 2, not stage 1. Do not skip stage 1.

Specific errors

ErrorAction
DOMAINS_UNSUPPORTED_TLDNot an error to the user — a branch. See §A6.
403 / access_denied on domain-search v2You added auth to a public endpoint. Remove all headers and retry.
Offering returns no products"Wix doesn't support purchasing this TLD. Try a different extension like .com, .net, or .org."
Intent upsert validation errorShow which fields are wrong, ask for corrections, retry. See §P5.
Cart add-items failsConfirm productId came from the offering response, not hardcoded. Retry once.
Anything else, persistentEscalation ladder above.

R9. Forbidden Actions

Never:

  • Expose internal mechanics — no API names, endpoint paths, tool names, error codes, HTTP status codes, field names, or phrases like "the request failed", "I'm calling the …", "saving to the intent API", "adding line items", "canceling the old cart".
  • Narrate work in progress: "Let me check…", "I'll look that up…", "Verifying…", "Hold on…". The only permitted progress line is "Setting up your order..." at cart build.
  • Invent a price, a cycle length, a suggestion, or a URL. Every price and cycle comes from the offering response; every suggestion comes from the suggest endpoint; every URL comes from §R6.
  • Copy a number out of an example. Every worked example in this document uses {placeholder} braces for exactly this reason. A concrete figure appearing in a template, a transcript, or your own knowledge of what domains usually cost is not data — it is a fabrication with a currency symbol in front of it. If the call that supplies a price could not be made, the flow stops (§P3). It does not continue with a plausible guess.
  • Attach a per-year period to a per-period price. Every figure in pricingDetails[]finalPrice and renewalPrice alike, domain and addon alike — is the charge for one whole cycle. A 3-year row's $107.50 is one three-year charge. /yr is correct on a 1-year term and on nothing else; for anything longer the wording is "every {N} years" or "for {N} years" (§P6, §P9). This is arithmetic the user does in their head, and the error is always in the expensive direction.
  • Divide or multiply a price to reach a per-year figure. The response carries monthlyTotal and lowestCyclePrice precisely because someone will be tempted; both are unverified in this skill and neither is a substitute for saying which period the price covers. Print the period, not a rate.
  • Re-check availability for a domain that came from the suggest endpoint.
  • Use availability.premium to decide anything.
  • Fetch list of sites when a siteId is already in context. A partial roster the host preloaded is not that — see Case A.
  • Announce a site count instead of the sites. "You have 93 sites — want me to list them?" asks permission for a step already required. Show them (§R3 Case B) — all of them up to eight, otherwise five and an invitation to name one.
  • Hedge about ownership the account already settled. Once §R4.3 returns an exact match, the domain is the user's — no "if it's yours", no "do you own this?", no "assuming it's yours". The hedge belongs to the branch where ownership is genuinely an inference, and nowhere else.
  • Treat a searchTerm hit as ownership. It is a substring search. Compare the returned domain string to the normalized domain exactly, or you will tell a user they own a domain they do not.
  • Hedge about a subdomain whose root domain the account holds. "If shop.maximz.fr is yours" to a user who owns maximz.fr asks them to vouch for something the account already proves. §R1.1 and §A3.1 settle this before any message goes out.
  • Check availability for a subdomain. It is not separately registrable, so there is no answer to get. Go straight to the ownership lookups (§A3.1).
  • Read a multi-label TLD as a subdomain. mybrand.co.uk is a root domain. Offering to connect co.uk is the failure the greedy extraction in §R1.1 exists to prevent.
  • Press the root-domain recommendation more than once. It is stated one time (§A3.1d). A user who has declined twice has decided, and the subdomain link still works without it.
  • Read anything but the match and the site name out of a My Domains response. Registrant names, addresses, phone numbers, expiry dates and contract IDs are all in there. None of it is in scope. The filter.msid variant adds one more permitted field and no others: the site's current primary domain.
  • Bind a domain with any part of the §R4.4 gate unmet. Ownership asserted rather than confirmed, no siteId, a Free site, or no affirmative answer — each one on its own is a stop. The connect link is the answer instead, and it is not a lesser one.
  • Move a domain between sites without naming the site it leaves. A bind re-assigns, so one POST can change two live sites. The offer names both before the user can agree to either (§C3.2d), and "want me to move it?" on its own is not that offer.
  • POST a bind the user has not agreed to. Not from silence, not from a repeated request, not from an ambiguous reply, not from "whatever you think". One explicit yes sits in front of every write, and a second, named yes in front of anything that displaces a live primary domain (§C3.3).
  • Guess a bindType. One of the two values replaces the address the site's visitors use. An unclear answer is asked again, never resolved by inference.
  • Read a field out of the bind response. Its shape has never been observed. A 2xx is the whole signal; anything else you claim to have read from it is invented.
  • Say "main address" for "primary domain" — or "main domain", "main URL", "root domain", or any other paraphrase. It is the product's term (§R4.4) and it is not yours to reword.
  • Promise anything about what happens after a bind — timing, propagation, SSL, certificates, "it may take a few hours". None of it comes from the call, and the DNS ban covers the rest.
  • Say what happens to the site a moved domain leaves behind — no "it'll go back to its wix.com address", no "your other domain will take over". Unknown, and unknowable from these calls.
  • Step outside the skill's scope on a taken domain. No WHOIS or registrant lookup, no naming the owner, no aftermarket/broker/acquisition advice, no valuation, no trademark opinion, no web browsing. A taken domain produces exactly one message — from whichever §A4b branch applies — and nothing is appended to it. The ownership check in §R4.3 is the sole exception, and it only ever looks inside the user's own account. Full boundary: §A1.1.
  • Use a tool this skill did not ask for. Having WHOIS, web search, or browsing available is not permission to use them. The information sources are the three in §R4 — that is the complete list.

Always:

  • Normalize the domain before every call.
  • Reuse the resolved siteId for the rest of the conversation.
  • Reveal information only when it changes what the user must do next.
  • Say the currency note (§R10) in the same message as any price shown to the user — and never name a currency or convert between two.
  • Check the §R4.4 gate before every bind, and offer the do-it-yourself link in the same breath as the offer to do it. The user is never left with only one of the two.

R10. Currency at Checkout

Every price this skill shows comes from the offering call as formattedAmount, which arrives with its own currency symbol already attached (§P3). Checkout is a separate surface and may present the charge in the user's own currency, so the figure in the conversation and the figure at the till can differ in currency. The skill cannot tell in advance, so it says exactly that much and no more.

One fixed sentence covers it, and it is the only thing this skill ever says about currency:

At checkout, prices may be shown in your local currency.

It goes in the same message as the prices it qualifies, once, wherever a currency amount is shown to the user — the period table, the privacy options and the pre-checkout summary (§P3, §P6 and §P9). In the summary it sits above the checkout link, so the link stays last.

Never:

  • Name a currency, or convert between two. "That's about €7.30" invents a figure and does arithmetic on a price in one move — §R9 forbids both. The sentence hedges precisely because the skill does not know what the checkout will show.
  • Reword it. No "approximate", no "excluding taxes", no "prices may vary", and no promise that the figure will be identical. It says what is known; everything else is invention.
  • Send it twice in one message, or send it on its own with no price beside it.
  • Attach it to "Free", to a percentage discount, or to the free-first-year clause (§P2.3). None of those is a currency amount, so there is nothing to localise.

Why this sits after Forbidden Actions rather than in numerical order. Renumbering §R9 would invalidate every reference to it across the document. A new section appended at the end costs nothing and breaks nothing.

Last updated: 16 August 2026

Did this help?