# Unstoppable Domains MCP Server

The Unstoppable Domains MCP (Model Context Protocol) server enables AI
assistants to help you search, purchase, and manage domain names through natural
conversation.

## What Can You Do?

With the MCP server, you can ask AI assistants to:

- **Search & Purchase Domains** - Find available domains, check pricing, and
  complete purchases
- **Manage Your Portfolio** - View your domains, filter by status, track
  expirations
- **Configure DNS** - Set up A records, CNAME, MX, TXT, and other DNS records
- **Sell on Marketplace** - List domains for sale, manage offers, negotiate with
  buyers
- **Communicate** - Contact domain sellers and manage conversations
- **Backorder Expiring Domains** - Place backorders on domains approaching
  expiration for automatic registration when they drop
- **AI Landing Pages** - Generate, monitor, and remove AI-powered landing pages
  for your domains

---

## Getting Started

### Connecting via OAuth (Recommended)

Most MCP-compatible tools support OAuth authentication:

1. Add the Unstoppable Domains MCP server to your AI tool
2. When prompted, authenticate via your browser
3. Authorize the requested permissions
4. Start using domain management commands

**Manage your connections:** Go to
[Account Settings](https://unstoppabledomains.com/account/settings) to view
connected apps, their scopes, and disconnect if needed.

### Connecting to AI Tools

| Tool                | Setup Method                                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Claude Code**     | `claude mcp add unstoppable-domains --transport http https://api.unstoppabledomains.com/mcp/v1/`   |
| **Claude Desktop**  | Add server config to your config file (see below)                                                             |
| **ChatGPT**         | Use the [REST API](#api-reference) via custom actions/functions (ChatGPT does not natively support MCP)       |
| **Bots & Scripts**  | Use the API endpoint with authentication header                                                               |
| **Other MCP Tools** | Follow tool-specific MCP server configuration                                                                 |

**Claude Desktop config:**

Add the following to your Claude Desktop config file:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
- **Linux:** `~/.config/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "unstoppable-domains": {
      "url": "https://api.unstoppabledomains.com/mcp/v1/"
    }
  }
}
```

---

## Authentication Options

### OAuth 2.0 (Recommended)

OAuth provides scoped access through browser-based authentication:

- **Easy setup** - Just authenticate when prompted
- **Granular permissions** - Only grant access to what you need
- **Revocable** - Disconnect apps anytime from Account Settings

**Available scopes:**

| Scope             | Access                                     |
| ----------------- | ------------------------------------------ |
| `domains:search`  | Search domains, check availability         |
| `portfolio:read`  | View your domains, DNS records, offers     |
| `portfolio:write` | Manage DNS, create listings, send messages |
| `cart:read`       | View cart and payment methods              |
| `cart:write`      | Add/remove cart items                      |
| `checkout`        | Complete purchases                         |

### API Key (Advanced)

For manual configuration or custom integrations:

1. Go to [Account Settings](https://unstoppabledomains.com/account/settings)
2. Scroll to bottom and click **Advanced**
3. Find the **MCP API Key** section
4. Generate a key (format: `ud_mcp_*`)
5. Copy your key (available anytime from this page)

Use the key in the Authorization header:

```
Authorization: Bearer ud_mcp_your_key_here
```

> **Security tip:** Store your API key in an environment variable to avoid
> exposing it in shell history or process listings:
>
> ```bash
> export UD_MCP_API_KEY="ud_mcp_your_key_here"
> # Then reference $UD_MCP_API_KEY in your scripts or configuration
> ```

> **Note:** API keys grant full access to all tools. Use OAuth for scoped
> access.

---

## Common Workflows

### Register a New Domain

```
"Find me available .com domains with 'coffee' in the name"
"Add coffeeshop.com to my cart"
"Create an ICANN contact with my business details"
"Complete the checkout"
```

**Tools used:** `ud_domains_search` → `ud_contact_create` →
`ud_cart_add_domain_registration` → `ud_cart_get_payment_methods` →
`ud_cart_checkout`

### Set Up DNS for a Website

```
"Show me the DNS records for mybrand.io"
"Add an A record pointing to 192.0.2.1"
"Add a CNAME record for www pointing to mybrand.io"
"Add MX records for Google Workspace"
```

**Tools used:** `ud_dns_records_list` → `ud_dns_record_add` (multiple)

### List a Domain for Sale

```
"List mydomain.com for sale at $5,000"
"Enable the offer feature with minimum $1,000"
"Show me any incoming offers"
"Accept the offer from buyer123"
```

**Tools used:** `ud_listing_create` → `ud_offers_list` → `ud_offer_respond`

### Buy from the Marketplace

```
"Search for premium.com"
"Add it to my cart with lease-to-own (12 months)"
"Show me my cart total"
"Generate a checkout link"
```

**Tools used:** `ud_domains_search` → `ud_cart_add_domain_listed` →
`ud_cart_get` → `ud_cart_get_payment_methods` → `ud_cart_checkout` (or
`ud_cart_get_url` for browser checkout)

### Buy from External Marketplaces (Afternic/Sedo)

```
"Search for business.com"
"I see it's listed on Afternic, add it to my cart"
"Complete the purchase"
```

**Tools used:** `ud_domains_search` → `ud_cart_add_domain_afternic` (or
`ud_cart_add_domain_sedo`) → `ud_cart_get_payment_methods` → `ud_cart_checkout`

**Note:** Search results include `marketplace.source` to indicate where the
domain is listed (afternic, sedo, or unstoppable_domains).

### Negotiate with a Seller

```
"Contact the seller of example.io"
"Send them a message asking about the price"
"Show me their reply"
```

**Tools used:** `ud_lead_get` → `ud_lead_message_send` →
`ud_lead_messages_list`

### Create an AI Landing Page

```
"Generate an AI landing page for mybrand.io"
"Check the status of my landing page generation"
"Remove the AI landing page from mybrand.io"
```

**Tools used:** `ud_domain_generate_lander` → `ud_domain_lander_status` →
`ud_domain_remove_lander`

### Download Landing Pages

```
"Download the landing page from mybrand.io so I can edit it"
```

**Tools used:** `ud_domain_download_lander`

---

## Portfolio-Wide Operations

12 tools support an `applyToAllDomainsInPortfolio` parameter that applies the
operation to **all** DNS domains in your portfolio, bypassing the normal
50-domain limit. When set to `true`, the `domains`/`records` parameter is ignored.

**How it works:**

1. Pass `applyToAllDomainsInPortfolio: true` to any supported tool
2. The operation is queued and processes all your domains in batches
3. Returns an `operationId` for reference (the bulk operation runs asynchronously in the background)

**Supported tools:**

- AI Landers: `ud_domain_generate_lander`, `ud_domain_remove_lander`
- DNS Records: `ud_dns_record_add`, `ud_dns_records_remove_all`
- DNS Nameservers: `ud_dns_nameservers_set_custom`, `ud_dns_nameservers_set_default`
- DNS Hosting: `ud_dns_hosting_add`, `ud_dns_hosting_remove`
- Domain Management: `ud_domain_tags_add`, `ud_domain_tags_remove`, `ud_domain_flags_update`, `ud_domain_auto_renewal_update`

Note: The `domains` (or `records` for `ud_dns_record_add`) parameter still requires at least one entry (used as a template for tools that need configuration), but individual domain names are ignored.

**Example — generate AI landers for entire portfolio:**

```json
{
  "domains": [{"name": "template.com"}],
  "applyToAllDomainsInPortfolio": true,
  "instructions": "Use warm earthy colors, focus on professional branding"
}
```

**Response:**

```json
{
  "applyToAllDomainsInPortfolio": true,
  "operationId": 12345,
  "message": "Operation queued for all portfolio domains. Track progress with ud_domain_pending_operations."
}
```

---

## Available Tools

> **Strict input validation:** Every tool rejects unknown or misspelled
> parameters at all nesting levels rather than silently ignoring them. A typo
> such as `price` instead of `priceInCents` produces a validation error, so use
> the exact parameter names documented for each tool.

### Domain Search

#### `ud_domains_search`

Search for domain availability and pricing across TLDs.

**Parameters:**

| Parameter | Type               | Required | Description                                                                                                   |
| --------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------- |
| `query`   | string or string[] | Yes      | Domain name(s) to search. Can be full domain ("example.com") or search term ("mybusiness"). Up to 10 queries. |
| `tlds`    | string[]           | No       | TLDs to search (e.g., ["com", "org", "io"]). Max 5. Use `ud_tld_list` to verify support.                      |
| `limit`   | number             | No       | Results to return (1-100, default: 20)                                                                        |
| `offset`  | number             | No       | Results to skip for pagination (default: 0)                                                                   |

**Example prompts:**

- "Search for available domains with 'startup' in the name"
- "Check if example.com is available"
- "Find .io domains containing 'dev'"

**Notes:**

- Not all ICANN TLDs are supported. Use `ud_tld_list` first to verify.
- Prices are returned in cents (USD).
- Results include `marketplace.source` to indicate where domains are listed:
  - `"unstoppable_domains"` - Use `ud_cart_add_domain_registration` (fresh registration) or
    `ud_cart_add_domain_listed` (marketplace listing)
  - `"afternic"` - Use `ud_cart_add_domain_afternic`
  - `"sedo"` - Use `ud_cart_add_domain_sedo`
- UD marketplace results include a `listingSettings` object with the seller's
  offer configuration:
  - `isOfferFeatureEnabled` (boolean) - Whether the seller accepts offers on
    this listing.
  - `minOfferAmountInCents` (number) - Minimum offer amount in cents the seller
    will consider.
  - `leaseToOwnOptions` (object) - Lease-to-own payment plan options, if
    configured.

---

#### `ud_tld_list`

List all available ICANN TLDs supported by the registrar.

**Parameters:** None

**Example prompts:**

- "What TLDs can I register?"
- "Show me all available domain extensions"
- "Is .ai supported?"

---

#### `ud_knowledge_base_search`

Search the Unstoppable Domains Knowledge Base for help articles by keyword. Returns matching articles ranked by relevance with titles, snippets, and direct links. Does not require authentication.

**Parameters:**

| Parameter | Type   | Required | Description                                                    |
| --------- | ------ | -------- | -------------------------------------------------------------- |
| `query`   | string | Yes      | Search term (2-200 characters). Matches against article titles and body text. |

**Example prompts:**

- "How do I transfer my domain?"
- "What is domain tokenization?"
- "Help with DNS setup"

---

#### `ud_developer_docs_search`

Search the public Unstoppable Domains developer documentation (rendered at https://docs.unstoppabledomains.com/) by keyword. Returns matching pages ranked by relevance with titles, snippets, and direct URLs. Use for SDK, API, smart-contract, namehashing, registrar API, and web3 integration questions. Does not require authentication.

**Parameters:**

| Parameter | Type   | Required | Description                                                                          |
| --------- | ------ | -------- | ------------------------------------------------------------------------------------ |
| `query`   | string | Yes      | Search term (2-200 characters). Matches against page titles and body text.           |

**Returns:**

- `articles`: Array of matching docs, each with `path` (within the dev-docs repo), `title`, `snippet`, `url` (rendered docs URL), and `score`
- `totalMatchCount`, `returnedCount` (max 20), `totalIndexedArticles`

**Example prompts:**

- "How do I resolve a UD domain in JavaScript?"
- "What's the namehash algorithm?"
- "Which contracts handle reverse resolution on Polygon?"

**Notes:**

- The dev-docs index is rebuilt on a 4-hour schedule from the public `unstoppabledomains/dev-docs` repo on GitHub
- Internal directories (`_partials/`, `docs/plans/`) are excluded from the index

---

#### `ud_api_specs_search`

Search across Unstoppable Domains' MCP server public specifications: `SKILL.md`, the MCP documentation page, and the OpenAPI 3.1 specification. Returns matching specs with titles, snippets, and direct URLs. Use for questions about the MCP server itself, available tools, OAuth scopes, or AI-agent integration. Does not require authentication.

**Parameters:**

| Parameter | Type   | Required | Description                                                            |
| --------- | ------ | -------- | ---------------------------------------------------------------------- |
| `query`   | string | Yes      | Search term (2-200 characters). Matches against spec titles and bodies. |

**Returns:**

- `articles`: Array of matching specs, each with `id` (`"skill"`, `"mcp_docs"`, or `"openapi"`), `title`, `snippet`, `url`, and `score`
- `totalMatchCount`, `returnedCount` (max 20), `totalIndexedArticles`

**Example prompts:**

- "What OAuth scopes does the MCP server use?"
- "Which MCP tools can add items to the cart?"
- "Where is the OpenAPI spec for the MCP server?"

---

### Portfolio Management

#### `ud_portfolio_list`

List domains in your portfolio with filtering and sorting.

**Parameters:**

| Parameter                 | Type     | Required | Description                                                                                                |
| ------------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `offset`                  | number   | No       | Number of items to skip for pagination (default: 0)                                                        |
| `limit`                   | number   | No       | Domains per page (1-500, default: 50)                                                                      |
| `searchTerm`              | string   | No       | Filter by domain name                                                                                      |
| `status`                  | string   | No       | "all", "for-sale", or "unlisted" (default: "all")                                                          |
| `registryType`            | string   | No       | "dns" (ICANN) or "web3" (default: "dns")                                                                   |
| `expiringWithinDays`      | number   | No       | Filter domains expiring within N days (1-365)                                                              |
| `expired`                 | boolean  | No       | Filter for expired domains                                                                                 |
| `minLength` / `maxLength` | number   | No       | Filter by domain label length                                                                              |
| `autoRenewal`             | string   | No       | "true" or "false"                                                                                          |
| `tagFilters`              | string[] | No       | Filter by tags (e.g., ["personal", "business"])                                                            |
| `orderBy`                 | string   | No       | Sort by: "name", "length", "purchasedAt", "expiresAt", "listingPrice", "offers", "leads", "watchlistCount" |
| `orderDirection`          | string   | No       | "asc" or "desc" (default: "asc")                                                                           |

**Example prompts:**

- "Show me all my domains"
- "List domains expiring in the next 30 days"
- "Show domains I have listed for sale, sorted by price"
- "Find my 4-letter domains"

---

#### `ud_domain_get`

Get comprehensive information for specific domains in your portfolio. Returns all
data from `ud_portfolio_list` plus additional detail: renewal pricing, flags, DNS
configuration, marketplace metrics, and pending operations.

**Parameters:**

| Parameter | Type     | Required | Description                                                          |
| --------- | -------- | -------- | -------------------------------------------------------------------- |
| `domains` | string[] | Yes      | Array of domain names to look up (e.g., ["example.com", "mysite.io"]) |

**Returns:**

- `domains`: Array with comprehensive info for each domain:
  - Identity: `domain`, `found`, `extension`, `label`, `sld`, `punycode`
  - `lifecycle`: Purchase date, expiration, transfer status, external ownership,
    reverse resolution, renewal pricing/eligibility, auto-renewal status
  - `flags`: Domain-level flags (WHOIS privacy, transfer lock, etc.)
  - `dns`: Nameservers (default/custom/none), hosting redirects, DNSSEC status
  - `marketplace`: Active listing details, offer/lead/watchlist counts
  - `tags`: Tags applied to this domain
  - `pendingOperations`: In-progress DNS or domain operations
  - `error`: Error message if retrieval failed
- `availableTags`: All tags you've created (useful for adding tags to other
  domains)

**Example prompts:**

- "Get detailed info for example.com and mysite.io"
- "Show me the renewal info, flags, and DNS config for my domains"
- "What's the listing and offer count on mybrand.com?"
- "Are there any pending operations on my domains?"

**Notes:**

- Maximum 50 domains per request
- Only ICANN DNS domains are fully supported
- DNS data (nameservers, hosting, DNSSEC) comes from cache and may be briefly
  delayed after changes
- All timestamps are in UTC (ISO 8601 format)

---

### ICANN Contacts

#### `ud_contacts_list`

List ICANN contacts for domain registration.

**Parameters:**

| Parameter         | Type    | Required | Description                                |
| ----------------- | ------- | -------- | ------------------------------------------ |
| `includeDisabled` | boolean | No       | Include disabled contacts (default: false) |

**Example prompts:**

- "Show my ICANN contacts"
- "List all registration contacts including disabled ones"

---

#### `ud_contact_create`

Create a new ICANN contact for DNS domain registration.

**Parameters:**

| Parameter       | Type   | Required | Description                                     |
| --------------- | ------ | -------- | ----------------------------------------------- |
| `firstName`     | string | Yes      | Contact first name                              |
| `lastName`      | string | Yes      | Contact last name                               |
| `email`         | string | Yes      | Contact email address                           |
| `phone`         | object | Yes      | `{ dialingPrefix: "+1", number: "5551234567" }` |
| `street`        | string | Yes      | Street address                                  |
| `city`          | string | Yes      | City                                            |
| `stateProvince` | string | Yes      | State/province code                             |
| `postalCode`    | string | Yes      | Postal/ZIP code                                 |
| `countryCode`   | string | Yes      | Two-letter ISO country code (e.g., "US")        |
| `organization`  | string | No       | Company name                                    |

**Example prompts:**

- "Create an ICANN contact for John Smith at 123 Main St, New York, NY 10001"
- "Add a business contact for Acme Corp"

**Notes:**

- Required before purchasing .com, .org, .net, and other ICANN domains.
- `phone.dialingPrefix` accepts both `"+1"` and `"1"` — the leading `"+"` is stripped before forwarding to the registrar.

---

### Cart Management

#### `ud_cart_get`

Get shopping cart contents with pricing breakdown.

**Parameters:**

| Parameter      | Type   | Required | Description         |
| -------------- | ------ | -------- | ------------------- |
| `discountCode` | string | No       | Promo code to apply |

**Example prompts:**

- "Show my cart"
- "What's in my shopping cart?"
- "Apply promo code SAVE20 to my cart"

---

#### `ud_cart_add_domain_registration`

Add primary (unregistered) domains to cart for fresh registration.

**Parameters:**

| Parameter            | Type   | Required | Description                            |
| -------------------- | ------ | -------- | -------------------------------------- |
| `domains`            | array  | Yes      | Array of domain objects                |
| `domains[].name`     | string | Yes      | Full domain name (e.g., "example.com") |
| `domains[].quantity` | number | No       | Registration years (1-10, default: 1)  |

**Example prompts:**

- "Add example.com to my cart"
- "Add mybrand.io for 2 years"
- "Add startup.com and startup.io to my cart"

**Response highlights:**

- `cart.subtotalFormatted` is the pre-discount total.
- `cart.totalAmountDueFormatted` is the price the user will actually pay.
- `cart.discounts[]` itemizes applied discounts. Quote `cart.totalAmountDueFormatted`, not the subtotal, when confirming the add.

---

#### `ud_cart_add_domain_listed`

Add marketplace-listed domains to cart (buy-now or lease-to-own).

**Parameters:**

| Parameter                                           | Type   | Required | Description                                                    |
| --------------------------------------------------- | ------ | -------- | -------------------------------------------------------------- |
| `domains`                                           | array  | Yes      | Array of domain objects (max 50)                               |
| `domains[].name`                                    | string | Yes      | Listed domain name                                             |
| `domains[].leaseToOwnOptions`                       | object | No       | Lease-to-own configuration                                     |
| `domains[].leaseToOwnOptions.type`                  | string | No       | "equal_installments" or "down_payment_plus_equal_installments" |
| `domains[].leaseToOwnOptions.termLength`            | number | No       | Payment term (2-120 months)                                    |
| `domains[].leaseToOwnOptions.downPaymentPercentage` | number | No       | Down payment (10-90%, required for down_payment type)          |

**Example prompts:**

- "Add premium.com to my cart"
- "Add premium.com with lease-to-own over 12 months"
- "Add premium.com with 20% down payment and 12 monthly installments"

**Notes:**

- Only for UD marketplace listings (`marketplace.source = "unstoppable_domains"`).
- The response includes `cart.totalAmountDueFormatted` and `cart.discounts[]`; use those to quote the actual amount due after discounts.
- For offer-only listings (`marketplace.status = "registered-listed-for-offers"`),
  domains cannot be added to cart. Direct users to the `purchaseUrl` from search
  results to make an offer. If `listingSettings.contactSellerEnabled` is true,
  users can also contact the seller via `ud_lead_get`.

---

#### `ud_cart_add_domain_afternic`

Add Afternic marketplace domains to cart.

**Parameters:**

| Parameter        | Type   | Required | Description                                   |
| ---------------- | ------ | -------- | --------------------------------------------- |
| `domains`        | array  | Yes      | Array of domain objects (max 50)              |
| `domains[].name` | string | Yes      | Domain name from Afternic (e.g., "brand.com") |

**Example prompts:**

- "Add brand.com from Afternic to my cart"
- "Purchase that Afternic domain"

**Notes:**

- Use for domains where search results show `marketplace.source = "afternic"`.
- The response includes `cart.totalAmountDueFormatted` and `cart.discounts[]`; use those to quote the actual amount due after discounts.
- Only works for domains with a buy-now price
  (`marketplace.status = "registered-listed-for-sale"`).
- For make-offer domains, direct users to the `purchaseUrl` from search results.

---

#### `ud_cart_add_domain_sedo`

Add Sedo marketplace domains to cart.

**Parameters:**

| Parameter        | Type   | Required | Description                                |
| ---------------- | ------ | -------- | ------------------------------------------ |
| `domains`        | array  | Yes      | Array of domain objects (max 50)           |
| `domains[].name` | string | Yes      | Domain name from Sedo (e.g., "premium.io") |

**Example prompts:**

- "Add premium.io from Sedo to my cart"
- "Purchase that Sedo domain"

**Notes:**

- Use for domains where search results show `marketplace.source = "sedo"`.
- The response includes `cart.totalAmountDueFormatted` and `cart.discounts[]`; use those to quote the actual amount due after discounts.
- Only works for domains with a buy-now price
  (`marketplace.status = "registered-listed-for-sale"`).
- For make-offer domains, direct users to the `purchaseUrl` from search results.

---

#### `ud_cart_add_domain_renewal`

Add domain renewals to cart.

**Parameters:**

| Parameter            | Type   | Required | Description                      |
| -------------------- | ------ | -------- | -------------------------------- |
| `domains`            | array  | Yes      | Array of domain objects (max 50) |
| `domains[].name`     | string | Yes      | Domain to renew (must own)       |
| `domains[].quantity` | number | No       | Renewal years (1-10, default: 1) |

**Example prompts:**

- "Renew example.com for 1 year"
- "Add 3-year renewal for mybrand.io"

**Response highlights:**

- `cart.subtotalFormatted` is the pre-discount total.
- `cart.totalAmountDueFormatted` is the price the user will actually pay.
- `cart.discounts[]` itemizes applied discounts. Quote `cart.totalAmountDueFormatted`, not the subtotal, when confirming the add.

---

#### `ud_cart_remove`

Remove items from cart.

**Parameters:**

| Parameter    | Type     | Required | Description                                |
| ------------ | -------- | -------- | ------------------------------------------ |
| `productIds` | string[] | Yes      | Product IDs to remove (from cart response) |

**Example prompts:**

- "Remove example.com from my cart"
- "Clear the domain I just added"

**Response highlights:**

- `cart.subtotalFormatted` is the remaining pre-discount total.
- `cart.totalAmountDueFormatted` is the remaining amount due after discounts.
- `cart.discounts[]` itemizes any discounts still applied.

---

### Payment & Checkout

#### `ud_cart_get_payment_methods`

Get saved payment methods and account balance.

**Parameters:** None

**Example prompts:**

- "Show my payment methods"
- "What's my account balance?"
- "What cards do I have on file?"

---

#### `ud_cart_add_payment_method_url`

Get a URL to add a new payment method (for example, when you don't have any
cards on file).

**Parameters:** None

**Example prompts:**

- "Give me a link to add a new card"
- "I don't have any payment methods, how do I add one?"
- "Generate a URL so I can add a payment method"

---

#### `ud_cart_checkout`

Complete checkout using saved payment method or account balance.

**Parameters:**

| Parameter           | Type    | Required | Description                         |
| ------------------- | ------- | -------- | ----------------------------------- |
| `paymentMethodId`   | string  | No       | Stripe payment method ID            |
| `useAccountBalance` | boolean | No       | Use account balance (default: true) |
| `discountCode`      | string  | No       | Promo code                          |
| `contactId`         | string  | No       | ICANN contact ID for DNS domains    |

**Example prompts:**

- "Complete my purchase using my account balance"
- "Checkout using my Visa ending in 4242"
- "Complete checkout with contact ID abc123"

**Notes:**

- Call `ud_cart_get_payment_methods` first to verify a payment method or
  sufficient account credits are available. Pass `paymentMethodId` if credits
  don't cover the cart total.
- For DNS domains (.com, .org, etc.), you must have an ICANN contact. Use
  `ud_contacts_list` to find your contact ID.
- On success, the response also includes `nextAction.handoffTo = "domainManager"`
  plus per-domain `nextAction.manageUrls` fallback links for post-purchase setup.

---

#### `ud_cart_get_url`

Generate a checkout URL for browser-based purchase.

**Parameters:**

| Parameter      | Type   | Required | Description             |
| -------------- | ------ | -------- | ----------------------- |
| `discountCode` | string | No       | Promo code for checkout |

**Example prompts:**

- "Give me a checkout link"
- "Generate a URL to complete my purchase"

---

### Marketplace Listings

#### `ud_listing_create`

Create marketplace listings to sell domains.

**Parameters:**

| Parameter                                         | Type    | Required | Description                                |
| ------------------------------------------------- | ------- | -------- | ------------------------------------------ |
| `domains`                                         | array   | Yes      | Array of listing objects (max 50)          |
| `domains[].domainName`                            | string  | Yes      | Domain to list                             |
| `domains[].priceInCents`                          | number  | No       | Buy-now price in cents (0 for offers-only) |
| `domains[].expiresAt`                             | string  | No       | Listing expiration (ISO 8601)              |
| `domains[].listingSettings`                       | object  | No       | Additional settings                        |
| `domains[].listingSettings.isOfferFeatureEnabled` | boolean | No       | Accept offers                              |
| `domains[].listingSettings.minOfferAmountInCents` | number  | No       | Minimum offer amount                       |
| `domains[].listingSettings.domainDisplayName`     | string  | No       | Custom display name (must match domain, case-insensitive) |
| `domains[].leaseToOwnOptions`                     | object  | No       | Lease-to-own configuration                 |
| `domains[].leaseToOwnOptions.type`                | string  | No       | "equal_installments" or "down_payment_plus_equal_installments" |
| `domains[].leaseToOwnOptions.maxTermLength`       | number  | No       | Maximum payment term (2-120 months)        |
| `domains[].leaseToOwnOptions.downPaymentPercentage` | number | No       | Down payment (10-90%, required for down_payment type) |

**Example prompts:**

- "List mydomain.com for $5,000"
- "List mydomain.com for offers only with $1,000 minimum"
- "List mydomain.com for $10,000 with lease-to-own option"

**Notes:**

- Prices are in cents (e.g., $5,000 = 500000 cents). Use `priceInCents` for the
  buy-now price — a misspelled or unknown field (e.g. `price`) is rejected with
  a validation error rather than silently ignored.
- Set `priceInCents` to 0 for offers-only listings.
- This tool uses `domainName` (not `name`) for the domain field, unlike most
  other tools that use `name`.
- Unknown fields are rejected. Each domain object and its nested
  `listingSettings` / `leaseToOwnOptions` objects only accept the parameters
  listed above; unrecognized keys produce a validation error.

---

#### `ud_listing_update`

Update existing marketplace listings.

**Parameters:**

| Parameter                    | Type   | Required | Description                      |
| ---------------------------- | ------ | -------- | -------------------------------- |
| `listings`                                         | array  | Yes      | Array of update objects (max 50) |
| `listings[].id`                                    | number | Yes      | Listing ID                       |
| `listings[].priceInCents`                          | number | No       | New price in cents               |
| `listings[].expiresAt`                             | string | No       | New expiration date              |
| `listings[].listingSettings`                       | object | No       | Updated settings                 |
| `listings[].listingSettings.isOfferFeatureEnabled` | boolean | No      | Accept offers                    |
| `listings[].listingSettings.minOfferAmountInCents` | number | No       | Minimum offer amount             |
| `listings[].listingSettings.domainDisplayName`     | string | No       | Custom display name (must match domain, case-insensitive) |
| `listings[].leaseToOwnOptions`                     | object | No       | Lease-to-own configuration       |
| `listings[].leaseToOwnOptions.type`                | string | No       | "equal_installments" or "down_payment_plus_equal_installments" |
| `listings[].leaseToOwnOptions.maxTermLength`       | number | No       | Maximum payment term (2-120 months) |
| `listings[].leaseToOwnOptions.downPaymentPercentage` | number | No     | Down payment (10-90%, required for down_payment type) |

**Example prompts:**

- "Change mydomain.com listing price to $7,500"
- "Enable offers on my listing with ID 12345"

**Notes:**

- Prices are in cents (e.g., $7,500 = 750000 cents). Use `priceInCents` for the
  new buy-now price — a misspelled or unknown field (e.g. `price`) is rejected
  with a validation error rather than silently ignored.
- Unknown fields are rejected. Each update object and its nested
  `listingSettings` / `leaseToOwnOptions` objects only accept the parameters
  listed above; unrecognized keys produce a validation error.

---

#### `ud_listing_cancel`

Cancel marketplace listings.

**Parameters:**

| Parameter    | Type     | Required | Description                    |
| ------------ | -------- | -------- | ------------------------------ |
| `listingIds` | number[] | Yes      | Listing IDs to cancel (max 50) |

**Example prompts:**

- "Cancel my listing for mydomain.com"
- "Remove mydomain.com from the marketplace"

---

#### `ud_offers_list`

List incoming offers on your domains.

**Parameters:**

| Parameter    | Type   | Required | Description                                         |
| ------------ | ------ | -------- | --------------------------------------------------- |
| `domainName` | string | No       | Filter by domain                                    |
| `group`      | string | No       | "active" or "sold"                                  |
| `offset`     | number | No       | Number of items to skip for pagination (default: 0) |
| `limit`      | number | No       | Offers to return (1-100, default: 20)               |

**Example prompts:**

- "Show me all incoming offers"
- "What offers do I have on mydomain.com?"
- "Show my accepted offers"

---

#### `ud_offer_respond`

Accept or reject offers on your domains at the offer's stated price.

This tool does **not** support counter-offers — only `accept` and `reject`.
To propose a counter, send a message via `ud_lead_message_send` instead.

**Parameters:**

| Parameter         | Type   | Required | Description                        |
| ----------------- | ------ | -------- | ---------------------------------- |
| `offers`          | array  | Yes      | Array of response objects (max 50) |
| `offers[].id`     | number | Yes      | Offer ID                           |
| `offers[].action` | string | Yes      | "accept" or "reject"               |

**Example prompts:**

- "Accept offer 12345"
- "Reject the $500 offer on mydomain.com"

---

### Domain Conversations

#### `ud_leads_list`

List domain conversation leads (buyer-seller messages).

**Parameters:**

| Parameter   | Type    | Required | Description                                         |
| ----------- | ------- | -------- | --------------------------------------------------- |
| `domain`    | string  | No       | Filter by domain name                               |
| `skipEmpty` | boolean | No       | Skip conversations with no messages (default: true) |
| `offset`    | number  | No       | Number of items to skip for pagination (default: 0) |
| `limit`     | number  | No       | Conversations to return (1-100, default: 20)        |

**Example prompts:**

- "Show my domain conversations"
- "List leads for mydomain.com"

---

#### `ud_lead_get`

Get or create a conversation with a domain seller.

**Parameters:**

| Parameter | Type   | Required | Description                            |
| --------- | ------ | -------- | -------------------------------------- |
| `domain`  | string | Yes      | Domain to inquire about                |
| `buyerId` | string | No       | Encoded buyer ID (for offer responses) |

**Example prompts:**

- "Contact the seller of premium.com"
- "Start a conversation about example.io"

---

#### `ud_lead_messages_list`

Get messages in a domain conversation.

**Parameters:**

| Parameter        | Type   | Required | Description                          |
| ---------------- | ------ | -------- | ------------------------------------ |
| `conversationId` | number | Yes      | Conversation ID                      |
| `cursor`         | string | No       | Pagination cursor for older messages |

**Example prompts:**

- "Show messages in conversation 12345"
- "What did the seller say?"

---

#### `ud_lead_message_send`

Send a message in a domain conversation.

**Parameters:**

| Parameter        | Type   | Required | Description                      |
| ---------------- | ------ | -------- | -------------------------------- |
| `conversationId` | number | Yes      | Conversation ID                  |
| `content`        | string | Yes      | Message text (1-1000 characters) |

**Example prompts:**

- "Send 'I'm interested in your domain' to conversation 12345"
- "Reply asking about their minimum price"

---

### DNS Records

#### `ud_dns_records_list`

List DNS records for a domain.

**Parameters:**

| Parameter | Type   | Required | Description                                         |
| --------- | ------ | -------- | --------------------------------------------------- |
| `domain`  | string | Yes      | Domain name                                         |
| `type`    | string | No       | Filter by record type (A, AAAA, CNAME, MX, TXT, NS, SRV, CAA) |
| `subName` | string | No       | Filter by subdomain                                 |
| `cursor`  | string | No       | Pagination cursor                                   |

**Example prompts:**

- "Show DNS records for mybrand.io"
- "List all MX records for example.com"
- "What A records does mydomain.com have?"

---

#### `ud_dns_record_add`

Add DNS records to one or more domains. Supports bulk operations up to 50
records.

**Parameters:**

| Parameter    | Type   | Required | Description                                                           |
| ------------ | ------ | -------- | --------------------------------------------------------------------- |
| `records`    | array  | Yes      | Array of record configurations (1-50)                                 |
| `upsertMode` | string | No       | Global: "append", "replace", or "disallowed" (default; applies to all records). Under "disallowed", any record whose `(type, subName)` already exists on the same domain is returned as a per-record failure with `error: "RECORD_ALREADY_EXISTS"`. |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. The first `records` entry is used as a template (individual domain names are ignored). Returns `operationId` for reference. |

**Record configuration:**

| Parameter | Type     | Required | Description                                        |
| --------- | -------- | -------- | -------------------------------------------------- |
| `domain`  | string   | Yes      | Domain name                                        |
| `type`    | string   | Yes      | Record type: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA |
| `values`  | string[] | Yes      | Record values                                      |
| `subName` | string   | No       | Subdomain (default: "@" for root)                  |
| `ttl`     | number   | No       | Time-to-live in seconds (60-86400, default: 3600)  |

**Example prompts:**

- "Add an A record for mybrand.io pointing to 192.0.2.1"
- "Add A records to mydomain.com and mybrand.io pointing to 192.0.2.1"
- "Add a CNAME for www.mybrand.io pointing to mybrand.io"
- "Add MX records for Google Workspace to all my domains"
- "Add a TXT record for domain verification"

**Notes:**

- `upsertMode` is a **top-level parameter** (not per-record). It applies
  globally to all records in the request.
- Use `subName: "@"` for root domain records.
- Use `upsertMode: "replace"` to overwrite existing records of the same
  type/subname.
- Bulk operations return per-record results with success/failure status.
- Under the default `"disallowed"` upsertMode, a record whose
  `(type, subName)` already exists on the same domain is **rejected
  synchronously** with `success: false` and
  `error: "RECORD_ALREADY_EXISTS"` — the existing record is preserved
  unchanged. Use `upsertMode: "append"` to add another value alongside the
  existing record, or `upsertMode: "replace"` to overwrite it.

**Example collision response:**

Calling `ud_dns_record_add` for a `TXT @` record on a domain that already
has a `TXT @` record (e.g. an existing SPF record) under the default
upsertMode:

```json
{
  "results": [
    {
      "domain": "aitripguides.com",
      "success": false,
      "error": "RECORD_ALREADY_EXISTS"
    }
  ],
  "successCount": 0,
  "failureCount": 1
}
```

---

#### `ud_dns_record_update`

Update existing DNS records on one or more domains. Supports bulk operations up
to 50 records.

**Parameters:**

| Parameter | Type  | Required | Description                           |
| --------- | ----- | -------- | ------------------------------------- |
| `records` | array | Yes      | Array of record update configs (1-50) |

**Record configuration:**

| Parameter  | Type     | Required | Description                            |
| ---------- | -------- | -------- | -------------------------------------- |
| `domain`   | string   | Yes      | Domain name                            |
| `recordId` | string   | Yes      | Record ID (from `ud_dns_records_list`) |
| `values`   | string[] | Yes      | New record values                      |
| `ttl`      | number   | No       | New TTL (60-86400, default: 3600)      |

**Example prompts:**

- "Update my A record to point to 192.0.2.2"
- "Change the TTL on record abc123 to 300 seconds"
- "Update A records across my domains to point to a new IP"

**Notes:**

- `values` is always required, even when only updating TTL. Re-supply the
  current values (from `ud_dns_records_list`) along with the new TTL.
- Bulk operations return per-record results with success/failure status.

---

#### `ud_dns_record_remove`

Remove specific DNS records from one or more domains. Supports bulk operations
up to 50 records.

**Parameters:**

| Parameter | Type  | Required | Description                            |
| --------- | ----- | -------- | -------------------------------------- |
| `records` | array | Yes      | Array of record removal configs (1-50) |

**Record configuration:**

| Parameter  | Type   | Required | Description         |
| ---------- | ------ | -------- | ------------------- |
| `domain`   | string | Yes      | Domain name         |
| `recordId` | string | Yes      | Record ID to remove |

**Example prompts:**

- "Delete the old A record"
- "Remove DNS record abc123"
- "Delete old A records from all my domains"

**Notes:**

- Bulk operations return per-record results with success/failure status.

---

#### `ud_dns_records_remove_all`

Remove ALL user-created DNS records from one or more domains. Supports bulk
operations up to 50 domains.

**Parameters:**

| Parameter          | Type    | Required | Description                                      |
| ------------------ | ------- | -------- | ------------------------------------------------ |
| `domains`          | array   | Yes      | Array of domains: `[{name: "example.com"}, ...]` |
| `confirmDeleteAll` | boolean | Yes      | Must be `true` to confirm deletion               |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Remove all DNS records from mybrand.io"
- "Clear all my custom DNS settings from all my domains"
- "Reset DNS records for mydomain.com and mybrand.io"

**Notes:**

- This is destructive. The `confirmDeleteAll: true` parameter is required.
- Bulk operations return per-domain results with success/failure status.

---

### DNS Nameservers

#### `ud_dns_nameservers_list`

List nameservers for a domain.

**Parameters:**

| Parameter       | Type    | Required | Description                |
| --------------- | ------- | -------- | -------------------------- |
| `domain`        | string  | Yes      | Domain name                |
| `includeDnssec` | boolean | No       | Include DNSSEC information |

**Example prompts:**

- "What nameservers is mybrand.io using?"
- "Show nameserver configuration with DNSSEC status"

---

#### `ud_dns_nameservers_set_custom`

Set custom (external) nameservers for one or more domains. Supports bulk
operations up to 50 domains.

**Parameters:**

| Parameter               | Type     | Required | Description                             |
| ----------------------- | -------- | -------- | --------------------------------------- |
| `domains`               | array    | Yes      | Array of domain configurations (max 50) |
| `domains[].name`        | string   | Yes      | Domain name                             |
| `domains[].nameservers` | string[] | Yes      | Nameserver hostnames (2-12 required)    |
| `domains[].dnssec`      | object   | No       | DNSSEC DS records                       |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Point mybrand.io to Cloudflare nameservers"
- "Set custom nameservers for mybrand.io and mybrand.net"
- "Configure Route 53 nameservers for all my domains"

**Notes:**

- Requires 2-12 nameserver hostnames per domain.
- DNS record management through this tool will be disabled when using custom
  nameservers.
- Supports partial success: some domains may succeed while others fail.

---

#### `ud_dns_nameservers_set_default`

Reset one or more domains to Unstoppable Domains default nameservers. Supports
bulk operations up to 50 domains.

**Parameters:**

| Parameter        | Type   | Required | Description               |
| ---------------- | ------ | -------- | ------------------------- |
| `domains`        | array  | Yes      | Array of domains (max 50) |
| `domains[].name` | string | Yes      | Domain name               |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Switch mybrand.io back to default nameservers"
- "Reset nameservers to UD defaults for all my domains"
- "Move mybrand.io and mybrand.net back to UD DNS"

**Notes:**

- Re-enables DNS record management through these tools.
- Supports partial success: some domains may succeed while others fail.

---

### DNS Hosting

#### `ud_dns_hosting_list`

List hosting/forwarding configurations.

**Parameters:**

| Parameter | Type   | Required | Description       |
| --------- | ------ | -------- | ----------------- |
| `domain`  | string | Yes      | Domain name       |
| `cursor`  | string | No       | Pagination cursor |

**Example prompts:**

- "Show hosting configuration for mybrand.io"
- "What redirects are set up for my domain?"

---

#### `ud_dns_hosting_add`

Add or update hosting configuration for one or more domains (for-sale page,
301/302 redirect). Uses an **upsert pattern** - calling this on a domain with
existing hosting will replace the configuration. Supports bulk operations up to
50 domains.

**Parameters:**

| Parameter                      | Type    | Required    | Description                                       |
| ------------------------------ | ------- | ----------- | ------------------------------------------------- |
| `domains`                      | array   | Yes         | Array of domain configurations (max 50)           |
| `domains[].name`               | string  | Yes         | Domain name                                       |
| `domains[].type`               | string  | Yes         | "LISTING_PAGE", "REDIRECT_301", or "REDIRECT_302" |
| `domains[].targetUrl`          | string  | Conditional | Required for redirects                            |
| `domains[].subName`            | string  | No          | Subdomain to configure                            |
| `domains[].forceCompatibility` | boolean | No          | Auto-configure nameservers if needed              |
| `applyToAllDomainsInPortfolio` | boolean | No          | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Set up a for-sale landing page for mybrand.io"
- "Add landing pages to all my listed domains"
- "Redirect mybrand.io and mybrand.net to https://mynewsite.com with 301"
- "Add a 302 redirect from old.mybrand.io to mybrand.io/new"
- "Change the redirect URL for mybrand.io to https://newsite.com"
- "Update my domain's redirect from temporary to permanent"

**Notes:**

- Each domain can have different hosting configurations.
- Supports partial success: some domains may succeed while others fail.

---

#### `ud_dns_hosting_remove`

Remove hosting/forwarding configuration from one or more domains. Supports bulk
operations up to 50 domains.

**Parameters:**

| Parameter             | Type    | Required    | Description                           |
| --------------------- | ------- | ----------- | ------------------------------------- |
| `domains`             | array   | Yes         | Array of domains (max 50)             |
| `domains[].name`      | string  | Yes         | Domain name                           |
| `domains[].subName`   | string  | No          | Subdomain to remove config from       |
| `domains[].deleteAll` | boolean | No          | Remove ALL hosting configs for domain |
| `confirmDeleteAll`    | boolean | Conditional | Required if any domain has deleteAll  |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Remove the redirect from mybrand.io"
- "Remove hosting from all my domains"
- "Delete all hosting configurations for mybrand.io and mybrand.net"

**Notes:**

- Supports partial success: some domains may succeed while others fail.

---

### Domain Operations

#### `ud_domain_pending_operations`

Check status of pending DNS operations across multiple domains. Supports bulk
operations up to 50 domains.

**Parameters:**

| Parameter          | Type    | Required | Description                                   |
| ------------------ | ------- | -------- | --------------------------------------------- |
| `domains`          | array   | Yes      | Array of domain objects (max 50)              |
| `domains[].name`   | string  | Yes      | Domain name                                   |
| `includeCompleted` | boolean | No       | Include operations completed in last 24 hours |

**Example prompts:**

- "Are there any pending DNS changes for mybrand.io?"
- "Check the status of my nameserver update"
- "Check pending operations for all my domains"
- "Are any of my DNS changes still processing?"

**Notes:**

- Returns a summary with `totalPendingCount` and `domainsWithPending` for easy
  monitoring.
- Use after bulk DNS record operations to track progress across all affected
  domains.
- Supports partial success: some domains may succeed while others fail.

---

#### `ud_domain_auto_renewal_update`

Enable or disable auto-renewal for ICANN domains.

**Parameters:**

| Parameter         | Type   | Required | Description                                      |
| ----------------- | ------ | -------- | ------------------------------------------------ |
| `action`          | string | Yes      | "enable" or "disable"                            |
| `domains`         | array  | Yes      | Array of domain objects (max 50)                 |
| `domains[].name`  | string | Yes      | Domain name                                      |
| `paymentMethodId` | string | No       | Payment method ID (uses default card if omitted) |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Enable auto-renewal for mybrand.io"
- "Turn off auto-renewal for example.com"
- "Enable auto-renewal for all my domains using my Visa"

**Notes:**

- When enabling, a payment method is used. If `paymentMethodId` is omitted, your
  default card will be used. Use `ud_cart_get_payment_methods` to see available
  methods.

---

### Domain Tags

#### `ud_domain_tags_add`

Add tags to domains in your portfolio. Creates new tags automatically if they
don't exist.

**Parameters:**

| Parameter | Type     | Required | Description                                                |
| --------- | -------- | -------- | ---------------------------------------------------------- |
| `domains` | string[] | Yes      | Array of domain names to add tags to (max 50)              |
| `tags`    | string[] | Yes      | Array of tag names to add (max 10 tags, 20 chars each)     |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Returns:**

- `results`: Array with result for each domain
- `newTagsCreated`: Tags that were newly created
- `successCount` / `failureCount`: Summary counts

**Example prompts:**

- "Add the 'Work' tag to mybrand.io"
- "Tag example.com and mysite.io as 'Important'"
- "Add tags 'Portfolio' and 'Premium' to my domains"

**Notes:**

- Tags are automatically created if they don't exist
- If a tag is already applied to a domain, it's silently skipped

---

#### `ud_domain_tags_remove`

Remove tags from domains in your portfolio.

**Parameters:**

| Parameter | Type     | Required | Description                                        |
| --------- | -------- | -------- | -------------------------------------------------- |
| `domains` | string[] | Yes      | Array of domain names to remove tags from (max 50) |
| `tags`    | string[] | Yes      | Array of tag names to remove (max 10)              |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Returns:**

- `results`: Array with result for each domain
- `successCount` / `failureCount`: Summary counts

**Example prompts:**

- "Remove the 'Old' tag from mybrand.io"
- "Remove tags 'Temp' and 'Draft' from my domains"
- "Untag example.com from 'Work'"

**Notes:**

- Tags that don't exist or aren't applied to a domain are silently skipped

---

### Domain Flags

#### `ud_domain_flags_update`

Update domain flags (WHOIS privacy, transfer lock) for domains in your
portfolio.

**Parameters:**

| Parameter              | Type   | Required | Description                                                           |
| ---------------------- | ------ | -------- | --------------------------------------------------------------------- |
| `domains`              | array  | Yes      | Array of domain names to update (max 50)                              |
| `flags`                | object | Yes      | Flags to update (at least one required)                               |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |
| `flags.DNS_TRANSFER_OUT` | object | No     | Transfer lock: `{ status: "ENABLED" }` (allowed) or `{ status: "DISABLED" }` (blocked) |
| `flags.DNS_WHOIS_PROXY`  | object | No     | WHOIS privacy: `{ status: "ENABLED" }` (hidden) or `{ status: "DISABLED" }` (public)   |

**Returns:**

- `results`: Array with result for each domain
- `successCount` / `failureCount`: Summary counts

**Example prompts:**

- "Enable WHOIS privacy for mybrand.io"
- "Lock transfers for my premium domains"
- "Disable transfer lock on example.com"
- "Hide my personal info on all my domains"

**Notes:**

- Only ICANN DNS domains are supported
- At least one flag must be specified

---

### Domain Push

#### `ud_domain_push`

Push domains to another Unstoppable Domains user. This transfers ownership of
domains from your account to another user's account. **Requires MFA (two-factor
authentication) enabled on your account.**

**Parameters:**

| Parameter         | Type     | Required | Description                                                                          |
| ----------------- | -------- | -------- | ------------------------------------------------------------------------------------ |
| `domains`         | string[] | Yes      | Array of domain names to push (max 50)                                               |
| `targetAccountId` | string   | Yes      | Recipient's account ID in format "adjective-noun-xxx" (e.g., "brave-tiger-k7m")      |
| `otpCode`         | string   | Yes      | 6-digit OTP code from your authenticator app                                         |

**Returns:**

- `success`: Whether any domains were successfully pushed
- `pushedDomains`: Domains that were initiated for push
- `failedDomains`: Domains that failed with reason and message
- `targetAccountId`: The target account ID
- `message`: Human-readable summary

**Example prompts:**

- "Push example.com to brave-tiger-k7m with OTP 123456"
- "Transfer mybrand.io to my friend's account"
- "Send these domains to another user"

**Notes:**

- **MFA Required**: You must have two-factor authentication (OTP) enabled on
  your account to use this feature
- The recipient must accept the transfer within 4 hours
- Only ICANN DNS domains can be pushed
- Cannot push expired domains or domains with pending transfers
- Cannot push domains to yourself
- Processing may take up to 10 minutes
- Maximum 50 domains per request
- Find the recipient's account ID in their account settings

---

### AI Credits

#### `ud_ai_credits_get`

Check your AI credit balance and view available credit packs for purchase. AI
credits are used to generate AI-powered landing pages (1 credit per domain).
Accounts receive a daily free top-up of up to 5 credits — the free balance is
refilled to a cap of 5 each PT calendar day the next time you touch an AI
surface.

**Parameters:** None

**Response:**

| Field                | Type   | Description                                     |
| -------------------- | ------ | ----------------------------------------------- |
| `balance`            | number | Current AI credit balance                       |
| `tiers`              | array  | Available credit packs                          |
| `tiers[].size`       | number | Number of credits in the pack                   |
| `tiers[].priceInCents` | number | Price in cents                                |
| `tiers[].priceFormatted` | string | Price as formatted string (e.g., "$20")     |
| `tiers[].productCode` | string | Product code for purchasing                    |
| `tiers[].pricePerCredit` | string | Cost per credit (e.g., "$0.60")             |
| `hint`               | string | Usage guidance                                  |

---

#### `ud_cart_add_ai_credits`

Add an AI credit pack to your shopping cart. Provide either a product code or
tier size.

**Parameters:**

| Parameter     | Type   | Required | Description                                         |
| ------------- | ------ | -------- | --------------------------------------------------- |
| `productCode` | string | No*      | Product code (e.g., "ai-credits-pack-25")           |
| `tierSize`    | number | No*      | Number of credits (e.g., 5, 25, 125)                |

\* At least one of `productCode` or `tierSize` must be provided.

**Available packs:** 5 ($5), 25 ($20), 125 ($75)

**Response highlights:**

- The response includes the added pack details plus `cart.totalAmountDueFormatted`
  and `cart.discounts[]` so the user can see the final amount due immediately.

---

### AI Landing Pages

#### `ud_domain_generate_lander`

Generate AI-powered landing pages for one or more domains. The AI creates a
custom HTML landing page based on the domain name and deploys it to cloud
storage.

**Parameters:**

| Parameter        | Type   | Required | Description                            |
| ---------------- | ------ | -------- | -------------------------------------- |
| `domains`        | array  | Yes      | Array of domain objects (max 50)       |
| `domains[].name` | string | Yes      | Domain name (e.g., "example.com")      |
| `instructions`   | string | No       | Custom instructions to guide AI generation (max 2000 chars). E.g., "Use a blue color scheme", "Focus on tech industry", "Include a pricing section". Applied to all domains. |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Generate an AI landing page for mybrand.io"
- "Create landing pages for all my premium domains"
- "Build an AI-powered website for coffeeshop.com"
- "Generate a landing page for mybrand.io with a dark theme and minimalist style"
- "Create a landing page for coffeeshop.com focused on local SEO with warm colors"

**Notes:**

- Generation is asynchronous. Use `ud_domain_lander_status` to track progress.
- Re-generating a lander for a domain replaces the previous one.
- Returns a job ID per domain for tracking.
- Use the optional `instructions` parameter to customize the generated page (tone, colors, content focus, target audience).

---

#### `ud_domain_lander_status`

Check the AI landing page generation status for one or more domains.

**Parameters:**

| Parameter        | Type   | Required | Description                            |
| ---------------- | ------ | -------- | -------------------------------------- |
| `domains`        | array  | Yes      | Array of domain objects (max 50)       |
| `domains[].name` | string | Yes      | Domain name (e.g., "example.com")      |

**Statuses:**

| Status       | Description                                                                     |
| ------------ | ------------------------------------------------------------------------------- |
| `pending`    | Generation job is queued and waiting to start                                   |
| `generating` | AI content is being generated                                                   |
| `processing` | Content uploaded to storage, hosting config propagating (will become `hosted`)   |
| `hosted`     | Landing page is live and hosted on the domain                                   |
| `failed`     | Generation failed (error details included)                                      |
| `none`       | No lander content exists for this domain                                        |

**Example prompts:**

- "Check the status of my landing page for mybrand.io"
- "Is my AI landing page ready yet?"
- "What's the generation status for my domains?"

---

#### `ud_domain_remove_lander`

Remove AI-generated landing pages from one or more domains. Deletes the hosted
content and removes the hosting configuration.

**Parameters:**

| Parameter        | Type   | Required | Description                                  |
| ---------------- | ------ | -------- | -------------------------------------------- |
| `domains`        | array  | Yes      | Array of domain objects (max 50)             |
| `domains[].name` | string | Yes      | Domain name (e.g., "example.com")            |
| `applyToAllDomainsInPortfolio` | boolean | No | When `true`, applies to ALL portfolio domains. `domains` is ignored. Returns `operationId` for tracking. |

**Example prompts:**

- "Remove the AI landing page from mybrand.io"
- "Delete the landing pages from all my domains"
- "Take down the AI-generated site for coffeeshop.com"

**Notes:**

- This is destructive - the landing page content is permanently deleted.
- Returns an operation ID per domain for tracking with
  `ud_domain_pending_operations`.

---

#### `ud_domain_download_lander`

Download existing hosted lander files from one or more domains. The response
format adapts to the content:

- **Single-page landers** (only `index.html`): Returns raw HTML as
  `htmlContent` — you can read and edit the HTML directly.
- **Multi-file sites** (HTML + CSS, JS, images, etc.): Returns a base64-encoded
  zip as `zipContent`.

**Parameters:**

| Parameter        | Type   | Required | Description                            |
| ---------------- | ------ | -------- | -------------------------------------- |
| `domains`        | array  | Yes      | Array of domain objects (max 50)       |
| `domains[].name` | string | Yes      | Domain name (e.g., "example.com")      |

**Response fields per domain:**

| Field         | Type   | Description                                         |
| ------------- | ------ | --------------------------------------------------- |
| `format`      | string | `"html"` (single-page) or `"zip"` (multi-file)     |
| `htmlContent` | string | Raw HTML string (when format is "html")             |
| `zipContent`  | string | Base64-encoded zip file (when format is "zip")      |

**Example prompts:**

- "Download the landing page from mybrand.io"
- "Back up all my domain landing pages"
- "Get the lander files for coffeeshop.com so I can edit them locally"

**Notes:**

- Domain must have existing lander content hosted.
- Check the `format` field to determine which content field to read.

---

### Backorders

#### `ud_expireds_list`

Browse and search the expireds / pending-delete domain marketplace. Lists
domains approaching expiration (`COMING_SOON`) or recently dropped and still in
the buy window (`AVAILABLE_BACKORDER`). Supports keyword expansion, character-
shape filtering, drop-time windows, and TLD include/exclude — designed so an
LLM caller can answer themed asks ("animal breeds dropping", "city + service
.coms", "short brandable .coms next week") in a single call.

**Parameters:**

| Parameter          | Type   | Required | Description                                                                                                                                                                                                                  |
| ------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queries`          | array  | No       | One or more search terms (literal modes, OR-combined) or a single natural-language phrase (semantic mode). Under literal modes, values containing "." are exact full-name matches; otherwise label substring (case-insensitive). Under `queryMode: "semantic"`, dotted values are embedded as text, NOT exact-matched — use a literal mode for full-name lookups. Up to 8 values. Any stem length is accepted; pick the most specific anchored mode the caller implies ("starts with ai" → `startsWith`). Pass for specific names, theme/keyword expansions, or semantic intent; leave unset for open-ended browse asks. |
| `queryMode`        | string | No       | `contains` (default), `startsWith`, `endsWith`, `exact`, `semantic`. Use `semantic` for natural-language similarity intent ("luxury travel domains", "crypto brandables") — cosine match over AI-generated descriptions, pass a single descriptive phrase. Semantic mode does not paginate and ignores `excludeTlds`, `bidsRange`, `watchlistRange`, `deletionAtRange`, `sortBy`, `sortDirection`, and `status` (`tlds`, `lengthRange`, and `labelShape` still apply; `labelShape` collapses `noDigits`/`noHyphens` to the narrower `lettersOnly` shape because the vector corpus only indexes two shapes). Use `startsWith` for human-name / brand-prefix queries to avoid substring noise. |
| `labelShape`       | string | No       | `lettersOnly` (a-z only), `noDigits`, `noHyphens`, `any` (default). `lettersOnly` strips numeric/hyphenated noise — recommended for brandable / curated picks.                                                              |
| `status`           | string | No       | `COMING_SOON` (not yet dropped) or `AVAILABLE_BACKORDER` (dropped, in buy window).                                                                                                                                           |
| `tlds`             | array  | No       | TLD allowlist (e.g. `["com","net","org","io","co","xyz","ai"]`).                                                                                                                                                             |
| `excludeTlds`      | array  | No       | TLD blocklist. Combined with `tlds` if both are passed; values must not overlap with `tlds`.                                                                                                                                |
| `lengthRange`      | array  | No       | `[min, max]` label-length filter. Use `0` for unbounded upper.                                                                                                                                                              |
| `bidsRange`        | array  | No       | `[min, max]` backorder-count filter. Use `0` for unbounded upper.                                                                                                                                                            |
| `watchlistRange`   | array  | No       | `[min, max]` watchlist-count filter. Use `0` for unbounded upper.                                                                                                                                                            |
| `deletionAtRange`  | array  | No       | `[startMs, endMs]` Unix-millisecond drop-time window. Both bounds must be ≥ 1e12 (or `0` for unbounded). Pre-compute via `Date.now()` and `Date.now() + window-ms`.                                                          |
| `sortBy`           | string | No       | `name`, `deletionAt` (default), `labelLength`, `watchlistCount`, `backorderCount`. Leave unset for the natural "soonest drop first" order; use `watchlistCount` / `backorderCount` (with `sortDirection: "DESC"`) only when the user explicitly asks for community-activity ranking. |
| `sortDirection`    | string | No       | `ASC` (default) or `DESC`.                                                                                                                                                                                                   |
| `offset`           | number | No       | Pagination offset (default: 0).                                                                                                                                                                                              |
| `limit`            | number | No       | Items per page (1-500, default: 50).                                                                                                                                                                                         |

**Response shape (per row):**

| Field          | Type   | Description                                                                                                                  |
| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `name`         | string | Full domain name (e.g. `example.com`)                                                                                        |
| `deletionDate` | string | Pre-formatted `YYYY-MM-DD` UTC drop date — copy directly into agent responses to avoid date-conversion errors on small models. |
| `status`       | string | `COMING_SOON` or `AVAILABLE_BACKORDER`                                                                                       |

**Example prompts:**

- "Animal breeds dropping in the next 24h"
- "Find available city + service .nets like phoenixplumber.net"
- "10 short brandable .com drops"
- "Domains containing 'paul' dropping in the next 5 days"
- "AI / ML domains dropping this week"

**Notes:**

- For concept queries, expand the concept into **up to 8 of the most
  distinctive keyword stems** and pass via `queries`. The schema caps `queries`
  at 8 entries per call. Any stem length works under any `queryMode`; pick the
  most specific anchored mode the caller implies ("starts with ai" →
  `startsWith`, "ending in ly" → `endsWith`). For open-ended browse asks ("good
  drops today", "best deals") with no user-supplied keyword, leave `queries`
  unset and use filters.
- `deletionDate` is the recommended field for rendering drop dates — small
  models (Haiku-class) struggle with Unix-ms → date arithmetic.
- When `deletionAtRange` is supplied, the default 4 PM EST cutoff is bypassed
  so historical windows are reachable.

#### `ud_backorder_create`

Create backorders for one or more expiring DNS domains. A backorder reserves a
domain that is approaching expiration or has already dropped (become available
for registration). The system monitors the domain and automatically attempts to
register it when it becomes available.

**Parameters:**

| Parameter                            | Type   | Required | Description                                                        |
| ------------------------------------ | ------ | -------- | ------------------------------------------------------------------ |
| `domains`                            | array  | Yes      | Array of domain backorder objects (max 50)                         |
| `domains[].name`                     | string | Yes      | Domain name to backorder (e.g., "example.com")                     |
| `domains[].contactId`                | string | Yes      | ICANN contact ID for domain registration                           |
| `domains[].availableAfterTimestamp`  | number | Yes      | Unix timestamp (ms) when domain becomes available (from search)    |

**Example prompts:**

- "Backorder the domain expiring-domain.com"
- "Place backorders on these expiring domains: domain1.com, domain2.net"
- "Register domain.com when it drops"

**Notes:**

- Payment is deducted from Account Balance upfront as a hold (refunded on
  failure/cancellation)
- The `availableAfterTimestamp` is obtained from domain search results (`ud_domain_search`)
- Domainer Club members get overdraft up to -$500 and promotional pricing
- A $3.99 service fee applies to domains that have already dropped
  (available-backorder); no fee for coming-soon domains
- Use `ud_contacts_list` to find your ICANN contact ID
- Maximum 50 domains per request

#### `ud_backorders_list`

List the authenticated user's domain backorders with optional filtering and
pagination. Status normalization is applied automatically (pending backorders
past their availability date are shown as in-progress, and those past the
120-minute execution window are shown as failed).

**Parameters:**

| Parameter | Type   | Required | Description                                                     |
| --------- | ------ | -------- | --------------------------------------------------------------- |
| `status`  | array  | No       | Filter by backorder status (e.g., ["pending", "in-progress"])   |
| `query`   | string | No       | Search by domain name (partial match)                           |
| `offset`  | number | No       | Pagination offset (default: 0)                                  |
| `limit`   | number | No       | Items per page (1-100, default: 20)                             |

**Example prompts:**

- "Show me my backorders"
- "List my pending backorders"
- "Search my backorders for example.com"

---

### Session Handoff

#### `ud_authenticated_url_get`

Generate a one-time URL that automatically signs the user into the
Unstoppable Domains website and lands them on a specific page. Use this
whenever the user needs to complete an action in the browser (e.g., adding a
payment method, managing account settings, reviewing an order).

**Parameters:**

| Parameter | Type   | Required | Description                                                                                                            |
| --------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `path`    | string | Yes      | A known SPA route to land on. Must match one of the supported path templates — passing an unknown path returns an error listing the valid templates. |

**Example valid paths:**

- `/` (home)
- `/cart`, `/checkout`
- `/dashboard`, `/manage`
- `/marketplace`, `/marketplace/auctions`, `/marketplace/pending-delete`
- `/account/activity`, `/account/settings`
- `/account/payments`, `/account/payments/card`, `/account/payments/auto-renewal`
- `/account/orders`, `/account/subscriptions`, `/account/ai-credits`
- `/account/auctions`, `/account/backorders`
- `/d/<domain>` (a specific domain lander), `/s/<domain>` (non-indexed lander)
- `/watchlist`, `/leads`, `/domains/offers`
- `/bulk-search`, `/list`, `/domains/dns/transfer-in`, `/domains/presets`

**Example prompts:**

- "Open my saved payment cards"
- "Take me to my AI credits subscription"
- "Send me a link to manage my domains"

**Notes:**

- Requires authentication.
- The returned URL is valid for **5 minutes**. Re-clicks within that window
  from a browser that's already signed in short-circuit cleanly — no "already
  used" error on a second click.
- For support handoffs, send users directly to
  `https://support.unstoppabledomains.com` — the SPA does not have a
  `/support` route, so this tool cannot link to it.

---

## API Reference

| Item               | Value                                                    |
| ------------------ | -------------------------------------------------------- |
| **Endpoint**       | `https://api.unstoppabledomains.com/mcp/v1/`             |
| **OpenAPI Spec**   | `https://api.unstoppabledomains.com/mcp/v1/openapi.json` |
| **Authentication** | `Authorization: Bearer <token>`                          |
| **Protocol**       | MCP (Model Context Protocol) over HTTP                   |

### Timestamps

All timestamps returned by the API are in **UTC** using ISO 8601 format (e.g.,
`2025-06-15T14:30:00.000Z`). When displaying dates and times to users, convert
to the user's local timezone for a better experience.

---

### DNS Presets

#### `ud_presets_list`

List all saved DNS presets (nameserver, DNS records, forwarding) for the
authenticated user. Also returns hardcoded provider presets (Cloudflare,
Route 53, GoDaddy, etc.).

**Parameters:** None

#### `ud_presets_save`

Create or update a DNS preset. Upserts by name — if a preset with the same name
exists, it is updated. Forwarding presets are keyed on (name + subdomain), so the
same name can have separate entries for root and subdomain configurations.

**Parameters:**

| Parameter                | Type    | Required | Description                                                                  |
| ------------------------ | ------- | -------- | ---------------------------------------------------------------------------- |
| `type`                   | string  | Yes      | Preset type: "nameserver", "dns", or "forwarding"                            |
| `name`                   | string  | Yes      | Preset name (used as identifier)                                             |
| `isDefault`              | boolean | No       | Auto-apply to new registrations (default: false)                             |
| `isDefaultForTransferIns`| boolean | No       | Auto-apply to domain transfers                                               |
| `values`                 | array   | NS only  | Nameserver hostnames (for type "nameserver")                                 |
| `records`                | array   | DNS only | DNS record sets with type, subName, values, ttl (for type "dns")             |
| `hostingType`            | string  | Fwd only | Forwarding type: REDIRECT_301, REDIRECT_302, etc. (for type "forwarding")    |
| `targetUrl`              | string  | No       | Target URL for redirect/proxy (for type "forwarding")                        |
| `subdomain`              | string  | No       | Subdomain to apply forwarding to (for type "forwarding")                     |

**Example prompts:**

- "Save my Cloudflare nameservers as a preset"
- "Create a DNS records preset with my standard A and CNAME records"
- "Set my Cloudflare preset as the default for new registrations"

#### `ud_presets_delete`

Delete a saved preset by type and name.

**Parameters:**

| Parameter | Type   | Required | Description                                       |
| --------- | ------ | -------- | ------------------------------------------------- |
| `type`    | string | Yes      | Preset type: "nameserver", "dns", or "forwarding" |
| `name`    | string | Yes      | Name of the preset to delete                      |

#### `ud_presets_apply`

Apply a saved preset to one or more domains. This is the key convenience tool —
instead of typing nameserver hostnames or DNS records, reference a saved preset
by name.

**Parameters:**

| Parameter                        | Type    | Required | Description                                       |
| -------------------------------- | ------- | -------- | ------------------------------------------------- |
| `type`                           | string  | Yes      | Preset type: "nameserver", "dns", or "forwarding" |
| `name`                           | string  | Yes      | Name of the saved preset to apply                 |
| `domains`                        | array   | Yes      | Domain names to apply the preset to (max 50)      |
| `applyToAllDomainsInPortfolio`   | boolean | No       | Apply to all DNS domains in portfolio              |

**Example prompts:**

- "Apply my Cloudflare preset to example.com"
- "Set all my domains to use my Route 53 nameservers"
- "Apply my website DNS preset to example.com and example.net"

**Notes:**

- DNS changes are enqueued and may take a moment to propagate
- Use `ud_domain_pending_operations` to check operation status
- Typical workflow: `ud_presets_list` → `ud_presets_apply` → `ud_domain_pending_operations`

---

## Troubleshooting

### Tools not appearing

**Claude Code:**

```bash
claude mcp list  # Check if server is configured
```

**Claude Desktop:**

- Restart the app completely
- Verify config file:
  `cat ~/Library/Application\ Support/Claude/claude_desktop_config.json`

### Authentication errors

- Verify your API key starts with `ud_mcp_`
- For OAuth, try disconnecting and reconnecting in Account Settings
- Check that your token hasn't expired

### "Domain not found" errors

- Verify you own the domain with `ud_portfolio_list`
- Check the domain name spelling
- Ensure you're using the full domain name (e.g., "example.com" not just
  "example")

### DNS changes not appearing

- DNS propagation can take up to 48 hours
- Use `ud_domain_pending_operations` to check operation status
- Verify you're using UD default nameservers (custom nameservers disable DNS
  management)

### Need help?

- Email: support@unstoppabledomains.com
- Website: https://unstoppabledomains.com
