> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bizzyco.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Domain Tools

> Manage domains, WHOIS contacts, and domain registrations

The Bizzy MCP server provides 24 tools for managing domains and their associated
registration data. These tools are organized into four categories: domains
(including availability search, registration purchase, verification, and
renewal), domain contacts, domain registrations, and DNS records.

<Note>
  Domain Contacts on this page are the registrant, admin, and tech contacts
  attached to a domain registration (WHOIS data). They are distinct from CRM
  Contacts (people in your address book) — see [Contact
  Tools](/mcp-server/tools/contacts) for those.
</Note>

## Domains

Tools for managing domain records used for DNS and email.

### searchDomainAvailability

Check whether one or more domains are available to register, with pricing.
Provide a fully-qualified `domain`, or a `query` label paired with one or more
`tlds`. This is read-only — it does not register a domain or charge anything.

**Permission:** `domains:read`

**Parameters:**

| Name     | Type            | Required | Default | Description                                                                         |
| -------- | --------------- | -------- | ------- | ----------------------------------------------------------------------------------- |
| `domain` | string          | No\*     | -       | A fully-qualified domain to check (e.g. `example.com`)                              |
| `query`  | string          | No\*     | -       | A second-level label, no TLD (e.g. `acme`), checked across `tlds`                   |
| `tlds`   | array of string | No       | `[com]` | TLDs to pair with `query` (e.g. `["com", "io", "co"]`). Ignored unless `query` set. |

\*Provide `domain`, or `query` (with optional `tlds`).

A single call checks at most 25 names (`query` × `tlds` counts one name per
TLD); larger fan-outs are rejected.

**Returns:** An array of results, one per requested name. Each entry has a
`status`:

* `ok` — the name was checked. Includes `available`, `premium`, and prices
  (integer cents USD with the standard markup applied, or `null` when the
  registry returns no price).
* `rate_limited` — the name could not be checked right now because the registrar
  rate limit was hit. The name was neither confirmed available nor taken — retry
  it shortly (`retryAfterMs`, when present, hints how long to wait) and do not
  treat it as registered. The rest of the batch is still returned, so retry only
  the affected names.

```json theme={null}
[
    {
        "status": "ok",
        "domain": "example.com",
        "available": true,
        "premium": false,
        "registrationPrice": 1200,
        "renewalPrice": 1200,
        "currency": "USD"
    },
    {
        "status": "rate_limited",
        "domain": "example.io",
        "retryAfterMs": 800
    }
]
```

***

### registerDomain

Purchase and register a domain for the organization. This is the real
registration action — the same flow as `POST /v1/domain-registrations` in the
REST API: it fetches a live quote, confirms availability with the registrar,
charges the account default payment method off-session, and queues domain
provisioning.

<Warning>
  This tool charges real money and a completed registration cannot be undone.
  Nothing is charged if the live quote exceeds `maxAmountCents`. In Bizzy
  agent chat, a human must approve each call before any charge. The MCP server
  has no approval flow, so this tool is only callable over MCP when the
  agent's `domain-registrations.purchase` write permission is explicitly set
  to **Allow** — at the default **Ask** level it is not exposed to MCP clients
  at all. The `purchase` sub-resource is scoped to this tool alone: allowing
  other domain-registration tools does not enable it, and the grant must be
  explicit — it is never inherited from a broader `domain-registrations`
  permission.
</Warning>

**Permission:** `domain-registrations.purchase:write` (default level **Ask** —
approval-gated in agent chat; over MCP, callable only at **Allow**)

**Parameters:**

| Name             | Type    | Required | Default | Description                                                                                                                                                                                                                                                               |
| ---------------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `domain`         | string  | Yes      | -       | The fully-qualified domain to register (e.g. `acme.com`)                                                                                                                                                                                                                  |
| `periodYears`    | number  | No       | 1       | Initial registration period in years (1–10)                                                                                                                                                                                                                               |
| `maxAmountCents` | number  | Yes      | -       | Hard spend ceiling in USD cents; the call fails with `PRICE_EXCEEDS_MAXIMUM` (and charges nothing) if the quote is higher                                                                                                                                                 |
| `autoRenew`      | boolean | No       | true    | Whether the registration renews automatically each year                                                                                                                                                                                                                   |
| `whoisPrivacy`   | boolean | No       | true    | Whether WHOIS privacy protection is enabled                                                                                                                                                                                                                               |
| `contact`        | object  | Yes      | -       | Registrant (WHOIS) contact: `firstName`, `lastName`, `address1`, `city`, `stateProvince`, `postalCode`, `country` (2-letter), `email`, `phone`, plus optional `label`, `address2`, `organizationName`, `jobTitle` (`jobTitle` is required when `organizationName` is set) |
| `idempotencyKey` | string  | Yes      | -       | Caller-controlled retry key. Generate a fresh UUID per distinct purchase attempt; reuse the exact same value when retrying — a reused key replays the original result instead of charging again                                                                           |

**Returns:** The queued provisioning operation:

```json theme={null}
{
    "operationId": "9f8c2b1a-4d3e-4a6b-8c1d-2e3f4a5b6c7d",
    "status": "queued",
    "domain": "acme.com"
}
```

Typed failures include `DOMAIN_UNAVAILABLE`, `PRICE_EXCEEDS_MAXIMUM`,
`PAYMENT_METHOD_REQUIRED`, and `PAYMENT_FAILED`. If provisioning cannot be
queued after a successful charge, the charge is automatically refunded
(`DOMAIN_REGISTRATION_ENQUEUE_FAILED`) — retry with a new `idempotencyKey`.

***

### verifyDomain

Start or check TXT ownership verification for an externally owned domain — the
same flow as `POST /v1/domains/{id}/verification` and
`POST /v1/domains/{id}/verification/check` in the REST API. If verification has
not started (or previously failed or expired), a new verification token is
issued, hourly background checking begins, and the TXT record to publish is
returned. If verification is already pending, one live DNS check runs
immediately instead. The tool is idempotent: a pending, unexpired token is never
rotated and no duplicate background checking is started, so it is safe to call
repeatedly to poll status.

**Permission:** `domains:write` (default level **Ask** — approval-gated in agent
chat; over MCP, callable only when the agent's `domains` write permission
resolves to **Allow**)

**Parameters:**

| Name       | Type          | Required | Default | Description                     |
| ---------- | ------------- | -------- | ------- | ------------------------------- |
| `domainId` | string (UUID) | Yes      | -       | The ID of the domain to verify. |

**Returns:** The verification state plus the TXT record to publish:

```json theme={null}
{
    "status": "pending",
    "initiated": true,
    "recordName": "_bizzy.example.com",
    "expectedValue": "bizzy-domain-verification=3f2a…",
    "attempts": 0,
    "verifiedAt": null,
    "expiresAt": "2026-07-11T00:00:00.000Z",
    "reason": "Publish the TXT record; verification is checked hourly."
}
```

`status` is `verified`, `pending`, or `failed`; `initiated` is `true` only when
this call issued a fresh token (publish `recordName`/`expectedValue` as a DNS
TXT record at the domain's DNS host). Verification expires after 7 days —
calling the tool again after expiry issues a new token.

***

### getDomainRenewalPrice

Preview the live renewal price for a registered domain, without charging
anything — the same quote as `GET /v1/domains/{id}/registration/renewal-price`
in the REST API, and the exact amount `renewDomain` will enforce its
`maxAmountCents` ceiling against. This is read-only.

**Permission:** `domains:read`

**Parameters:**

| Name          | Type          | Required | Default | Description                               |
| ------------- | ------------- | -------- | ------- | ----------------------------------------- |
| `domainId`    | string (UUID) | Yes      | -       | The ID of the registered domain to price. |
| `periodYears` | number        | No       | 1       | Renewal period in years (1–10).           |

**Returns:** The live renewal quote in integer USD cents (standard markup
applied):

```json theme={null}
{
    "domain": "acme.com",
    "periodYears": 1,
    "amountCents": 1800,
    "currency": "usd",
    "premium": false
}
```

Fails with `DOMAIN_NOT_REGISTERED` for verified-only domains and
`DOMAIN_PRICE_UNAVAILABLE` when the registrar cannot return a live price.

***

### renewDomain

Renew a registered domain for the organization. This is the real renewal action
— the same flow as `POST /v1/domains/{id}/registration/renew` in the REST API:
it checks the live price against your ceiling, queues a renewal operation, and
the renewal workflow charges the account default payment method off-session,
renews the domain at the registrar, and extends the expiration date.

<Warning>
  This tool charges real money. Nothing is charged if the live price exceeds
  `maxAmountCents`; if the registrar renewal fails after the charge, the
  charge is automatically refunded. In Bizzy agent chat, a human must approve
  each call before any charge. The MCP server has no approval flow, so this
  tool is only callable over MCP when the agent's
  `domain-registrations.renewal` write permission is explicitly set to
  **Allow** — at the default **Ask** level it is not exposed to MCP clients at
  all. The `renewal` sub-resource is scoped to this tool alone: allowing other
  domain-registration tools does not enable it, and the grant must be explicit
  — it is never inherited from a broader `domain-registrations` permission.
</Warning>

**Permission:** `domain-registrations.renewal:write` (default level **Ask** —
approval-gated in agent chat; over MCP, callable only at **Allow**)

**Parameters:**

| Name             | Type          | Required | Default | Description                                                                                                                                                                                                                                                                          |
| ---------------- | ------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `domainId`       | string (UUID) | Yes      | -       | The ID of the registered domain to renew                                                                                                                                                                                                                                             |
| `periodYears`    | number        | No       | 1       | Renewal period in years (1–10)                                                                                                                                                                                                                                                       |
| `maxAmountCents` | number        | Yes      | -       | Hard spend ceiling in USD cents; the call fails with `PRICE_EXCEEDS_MAXIMUM` (and charges nothing) if the live price is higher                                                                                                                                                       |
| `idempotencyKey` | string        | Yes      | -       | Caller-controlled retry key. Generate a fresh UUID per distinct renewal attempt; reuse the exact same value (and the original `periodYears`/`maxAmountCents`) when retrying — a reused key replays the original result instead of renewing again; mismatched parameters are rejected |

**Returns:** The queued renewal operation, with the pre-flight quote
(`amountCents` is `null` when the call replayed an existing operation):

```json theme={null}
{
    "operationId": "9f8c2b1a-4d3e-4a6b-8c1d-2e3f4a5b6c7d",
    "status": "queued",
    "domain": "acme.com",
    "amountCents": 1800
}
```

Typed failures include `DOMAIN_NOT_REGISTERED`, `PRICE_EXCEEDS_MAXIMUM`, and
`DOMAIN_RENEWAL_ENQUEUE_FAILED` (nothing was charged — retry with a new
`idempotencyKey`).

***

### createDomain

Create a new domain record for DNS and email management.

**Permission:** `domains:write`

**Parameters:**

| Name        | Type                  | Required | Default   | Description                                     |
| ----------- | --------------------- | -------- | --------- | ----------------------------------------------- |
| `domain`    | string                | Yes      | -         | The domain name (e.g., example.com)             |
| `status`    | string                | No       | "pending" | Domain status (e.g., active, pending, inactive) |
| `zoneId`    | string \| null        | No       | -         | Optional DNS zone ID for the domain             |
| `createdBy` | string (UUID) \| null | No       | -         | Optional user ID who created the domain         |

<Note>
  Verification, registrar, and Resend-related fields are managed by the
  platform — do not pass them in here, as they are overwritten or ignored.
</Note>

**Returns:** The created domain object.

***

### getDomain

Get a specific domain by ID.

**Permission:** `domains:read`

**Parameters:**

| Name | Type          | Required | Description                      |
| ---- | ------------- | -------- | -------------------------------- |
| `id` | string (UUID) | Yes      | The ID of the domain to retrieve |

**Returns:** Domain object, or `null` if not found.

***

### listDomains

List all domains for the organization with pagination.

**Permission:** `domains:read`

**Parameters:**

| Name        | Type   | Required | Default | Description                                   |
| ----------- | ------ | -------- | ------- | --------------------------------------------- |
| `limit`     | number | No       | 10      | Maximum number of items to return (max: 100)  |
| `offset`    | number | No       | 0       | Number of items to skip for pagination        |
| `sortOrder` | string | No       | "desc"  | Sort order by creation date ("asc" or "desc") |

**Returns:**

```json theme={null}
{
  "domains": [...],
  "count": 12,
  "limit": 10,
  "offset": 0
}
```

***

### updateDomain

Update an existing domain record.

**Permission:** `domains:write`

**Parameters:**

| Name        | Type                  | Required | Description                         |
| ----------- | --------------------- | -------- | ----------------------------------- |
| `id`        | string (UUID)         | Yes      | The ID of the domain to update      |
| `domain`    | string                | No       | The domain name (e.g., example.com) |
| `createdBy` | string (UUID) \| null | No       | User ID who created the domain      |

Lifecycle and registration fields — `status`, `source`, `zoneId`, and
`expiresAt` — are not writable through this tool; they are managed by Bizzy
(expiry sweeps, renewals, registrar events, and zone provisioning).

**Returns:** The updated domain object.

***

### deleteDomain

Delete a domain (soft delete). Verified (externally registered) domains can be
deleted at any time; their DNS records at the external DNS host are left
untouched. Registered (Bizzy-managed) domains can only be deleted once their
registration has expired **and** their DNS zone holds no records beyond the
zone's built-in ones (the apex NS set and SOA) — disable email for the domain
first so Bizzy removes the email records it manages, then delete any remaining
records with the DNS record tools. A renewal that is already queued or running
also blocks the deletion until it finishes. A blocked deletion fails with
`REGISTERED_DOMAIN_NOT_EXPIRED`, `REGISTERED_DOMAIN_RENEWAL_IN_FLIGHT`, or
`REGISTERED_DOMAIN_DNS_NOT_EMPTY`; the last names the blocking records.

If the domain had email enabled, Bizzy also retires its email configuration —
revoking the sending credential and removing the domain from the email provider.
That cleanup is best-effort: if the provider is unreachable, the deletion still
goes through and any credential Bizzy could not revoke is recorded rather than
lost track of.

**Permission:** `domains:delete`

**Parameters:**

| Name | Type          | Required | Description                    |
| ---- | ------------- | -------- | ------------------------------ |
| `id` | string (UUID) | Yes      | The ID of the domain to delete |

**Returns:** The deleted domain object.

***

## Domain Contacts

Tools for managing the registration contacts used as the registrant on domains
registered through Bizzy. These are WHOIS-style contacts held at the domain
registrar — not CRM contacts.

Contacts are organization-wide: the same contact can be the registrant for any
number of domains. Writes go through to the registrar, so what these tools
change is also what appears in the public WHOIS record.

<Note>
  `externalId` and `accountId` identify the contact at the registrar and are
  assigned when it is created. They are returned on the contact object and
  cannot be supplied or changed by a caller.
</Note>

When one of these tools refuses a request, it comes back the way every MCP tool
result does — as a text block describing what happened, not a status code or an
error object. The refusal messages are quoted below so you know what to look
for.

### createDomainContact

Create a registration contact at the domain registrar and store it. Usable as
the registrant when registering a domain.

**Permission:** `domain-contacts:write`

**Parameters:**

| Name               | Type          | Required | Description                                                                                      |
| ------------------ | ------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `domainId`         | string (UUID) | No       | Domain this contact is for. Decides which registrar holds it; defaults to the platform registrar |
| `label`            | string        | No       | Label for your own organization. Never sent to the registrar                                     |
| `firstName`        | string        | Yes      | First name of the contact                                                                        |
| `lastName`         | string        | Yes      | Last name of the contact                                                                         |
| `organizationName` | string        | No       | Organization/company name                                                                        |
| `jobTitle`         | string        | No       | Job title. Required when `organizationName` is set                                               |
| `address1`         | string        | Yes      | Primary address line                                                                             |
| `address2`         | string        | No       | Secondary address line                                                                           |
| `city`             | string        | Yes      | City                                                                                             |
| `stateProvince`    | string        | Yes      | State or province                                                                                |
| `postalCode`       | string        | Yes      | Postal/ZIP code                                                                                  |
| `country`          | string        | Yes      | ISO-3166 alpha-2 country code (e.g., US, CA)                                                     |
| `email`            | string        | Yes      | Contact email address                                                                            |
| `phone`            | string        | Yes      | Contact phone number in E.164 format                                                             |

The address fields are required even though they are nullable on the stored
record: the registry rejects an incomplete registrant.

**Returns:** The created domain contact object, carrying the registrar-assigned
`externalId` and `accountId`.

***

### getDomainContact

Get a specific domain contact by ID.

**Permission:** `domain-contacts:read`

**Parameters:**

| Name | Type          | Required | Description                              |
| ---- | ------------- | -------- | ---------------------------------------- |
| `id` | string (UUID) | Yes      | The ID of the domain contact to retrieve |

**Returns:** Domain contact object, or `null` if not found.

***

### listDomainContacts

List all domain contacts for the organization with pagination.

**Permission:** `domain-contacts:read`

**Parameters:**

| Name        | Type   | Required | Default | Description                                   |
| ----------- | ------ | -------- | ------- | --------------------------------------------- |
| `limit`     | number | No       | 10      | Maximum number of items to return (max: 100)  |
| `offset`    | number | No       | 0       | Number of items to skip for pagination        |
| `sortOrder` | string | No       | "desc"  | Sort order by creation date ("asc" or "desc") |

**Returns:**

```json theme={null}
{
  "domainContacts": [...],
  "count": 8,
  "limit": 10,
  "offset": 0
}
```

***

### updateDomainContact

Update a registration contact at the domain registrar and in Bizzy.

**Permission:** `domain-contacts:write`

<Warning>
  Changing `firstName`, `lastName`, `organizationName`, or `email` restarts
  ICANN's 15-day registrant email verification on **every** domain using this
  contact as its registrant. Address and phone changes do not. See
  [Registration Contacts](/user-guide/domains/contacts).
</Warning>

**Parameters:**

| Name               | Type           | Required | Description                                                  |
| ------------------ | -------------- | -------- | ------------------------------------------------------------ |
| `id`               | string (UUID)  | Yes      | The ID of the domain contact to update                       |
| `label`            | string         | No       | Label for your own organization. Never sent to the registrar |
| `firstName`        | string         | No       | First name of the contact                                    |
| `lastName`         | string         | No       | Last name of the contact                                     |
| `organizationName` | string \| null | No       | Organization/company name                                    |
| `jobTitle`         | string \| null | No       | Job title. Required when `organizationName` is set           |
| `address1`         | string         | No       | Primary address line                                         |
| `address2`         | string \| null | No       | Secondary address line                                       |
| `city`             | string         | No       | City                                                         |
| `stateProvince`    | string         | No       | State or province                                            |
| `postalCode`       | string         | No       | Postal/ZIP code                                              |
| `country`          | string         | No       | ISO-3166 alpha-2 country code (e.g., US, CA)                 |
| `email`            | string         | No       | Contact email address                                        |
| `phone`            | string         | No       | Contact phone number in E.164 format                         |

A `label`-only change is local and never reaches the registrar, so it is allowed
even on a contact whose registration details are fixed.

Some contacts cannot have their registration details changed after registration.
Attempting it fails with the text `Error: This operation (registrant contact
updates) is not available` — create a new contact instead.

**Returns:** The updated domain contact object.

***

### deleteDomainContact

Remove a registration contact from Bizzy and from the domain registrar.

**Permission:** `domain-contacts:delete`

**Parameters:**

| Name | Type          | Required | Description                            |
| ---- | ------------- | -------- | -------------------------------------- |
| `id` | string (UUID) | Yes      | The ID of the domain contact to delete |

Refused while the contact is still the registrant of a live domain. The call
fails with the text `Error: This contact is the registrant for example.com and
cannot be removed`, naming every domain that is using it. Point those domains at
a different registrant first.

**Returns:** The deleted domain contact object.

***

## Domain Registrations

Tools for managing domain registration records that track ownership, renewal,
and registrar metadata.

### createDomainRegistration

Create a new domain registration record to track domain ownership and renewal.

**Permission:** `domain-registrations:write`

**Parameters:**

| Name               | Type                  | Required | Description                                             |
| ------------------ | --------------------- | -------- | ------------------------------------------------------- |
| `state`            | string                | Yes      | Registration state (e.g., registered, pending, expired) |
| `externalDomainId` | string                | Yes      | External domain ID from the registrar                   |
| `externalId`       | string                | Yes      | External registration ID from the registrar             |
| `autoRenew`        | boolean               | Yes      | Whether auto-renewal is enabled                         |
| `whoisPrivacy`     | boolean               | Yes      | Whether WHOIS privacy is enabled                        |
| `transferLock`     | boolean               | Yes      | Whether domain transfer lock is enabled                 |
| `period`           | number                | Yes      | Registration period in years                            |
| `domainId`         | string (UUID) \| null | No       | Optional reference to the related domain record         |
| `createdBy`        | string (UUID) \| null | No       | Optional user ID who created the registration           |

**Returns:** The created domain registration object.

***

### getDomainRegistration

Get a specific domain registration by ID.

**Permission:** `domain-registrations:read`

**Parameters:**

| Name             | Type          | Required | Description                                   |
| ---------------- | ------------- | -------- | --------------------------------------------- |
| `registrationId` | string (UUID) | Yes      | The ID of the domain registration to retrieve |

**Returns:** Domain registration object, or `null` if not found.

***

### listDomainRegistrations

List all domain registrations for the organization with pagination.

**Permission:** `domain-registrations:read`

**Parameters:**

| Name        | Type   | Required | Default | Description                                   |
| ----------- | ------ | -------- | ------- | --------------------------------------------- |
| `limit`     | number | No       | 10      | Maximum number of items to return (max: 100)  |
| `offset`    | number | No       | 0       | Number of items to skip for pagination        |
| `sortOrder` | string | No       | "desc"  | Sort order by creation date ("asc" or "desc") |

**Returns:**

```json theme={null}
{
  "domainRegistrations": [...],
  "count": 5,
  "limit": 10,
  "offset": 0
}
```

***

### updateDomainRegistration

Update an existing domain registration record - all fields are optional except
registrationId.

**Permission:** `domain-registrations:write`

**Parameters:**

| Name               | Type                  | Required | Description                                                        |
| ------------------ | --------------------- | -------- | ------------------------------------------------------------------ |
| `registrationId`   | string (UUID)         | Yes      | The ID of the domain registration to update                        |
| `state`            | string                | No       | Update the registration state (e.g., registered, pending, expired) |
| `externalDomainId` | string                | No       | Update the external domain ID from the registrar                   |
| `externalId`       | string                | No       | Update the external registration ID from the registrar             |
| `autoRenew`        | boolean               | No       | Update whether auto-renewal is enabled                             |
| `whoisPrivacy`     | boolean               | No       | Update whether WHOIS privacy is enabled                            |
| `transferLock`     | boolean               | No       | Update whether domain transfer lock is enabled                     |
| `period`           | number                | No       | Update the registration period in years                            |
| `createdBy`        | string (UUID) \| null | No       | Update the user ID who created the registration                    |

**Returns:** The updated domain registration object.

***

### deleteDomainRegistration

Delete a domain registration (soft delete).

**Permission:** `domain-registrations:delete`

**Parameters:**

| Name             | Type          | Required | Description                                 |
| ---------------- | ------------- | -------- | ------------------------------------------- |
| `registrationId` | string (UUID) | Yes      | The ID of the domain registration to delete |

**Returns:** The deleted domain registration object.

***

## Domain DNS Records

Tools for managing a registered domain's DNS records. DNS is backed by
Cloudflare (the customer DNS account is the system of record — records are not
stored in Bizzy). These tools only work for domains **registered through
Bizzy**; the DNS zone is created automatically the first time a record is added.

### listDnsRecords

List the DNS records for a registered domain. Returns an empty list if the
domain has no DNS zone yet.

**Permission:** `domains:read`

**Parameters:**

| Name       | Type          | Required | Description                          |
| ---------- | ------------- | -------- | ------------------------------------ |
| `domainId` | string (UUID) | Yes      | The domain whose DNS records to list |

**Returns:**

```json theme={null}
{
  "dnsRecords": [...],
  "count": 4
}
```

***

### createDnsRecord

Create a DNS record for a registered domain.

**Permission:** `domains:write`

**Parameters:**

| Name       | Type          | Required | Default | Description                                                  |
| ---------- | ------------- | -------- | ------- | ------------------------------------------------------------ |
| `domainId` | string (UUID) | Yes      | -       | The domain to add the DNS record to                          |
| `type`     | string        | Yes      | -       | Record type: A, AAAA, CNAME, MX, TXT, SRV, CAA, or NS        |
| `name`     | string        | Yes      | -       | Record name (use `@` for the root domain)                    |
| `content`  | string        | Yes      | -       | Record value (e.g. an IP address or target hostname)         |
| `ttl`      | number        | No       | 3600    | Time-to-live in seconds (60–86400)                           |
| `proxied`  | boolean       | No       | -       | Whether traffic is proxied through Cloudflare (A/AAAA/CNAME) |
| `priority` | number        | No       | -       | Priority (required for MX and SRV records)                   |

**Returns:** The created DNS record object.

***

### updateDnsRecord

Update a DNS record. This is a full replacement — provide all record fields.

**Permission:** `domains:write`

**Parameters:**

| Name       | Type          | Required | Default | Description                                                  |
| ---------- | ------------- | -------- | ------- | ------------------------------------------------------------ |
| `domainId` | string (UUID) | Yes      | -       | The domain the DNS record belongs to                         |
| `recordId` | string        | Yes      | -       | The DNS record ID to update                                  |
| `type`     | string        | Yes      | -       | Record type: A, AAAA, CNAME, MX, TXT, SRV, CAA, or NS        |
| `name`     | string        | Yes      | -       | Record name (use `@` for the root domain)                    |
| `content`  | string        | Yes      | -       | Record value (e.g. an IP address or target hostname)         |
| `ttl`      | number        | No       | 3600    | Time-to-live in seconds (60–86400)                           |
| `proxied`  | boolean       | No       | -       | Whether traffic is proxied through Cloudflare (A/AAAA/CNAME) |
| `priority` | number        | No       | -       | Priority (required for MX and SRV records)                   |

**Returns:** The updated DNS record object.

***

### deleteDnsRecord

Delete a DNS record from a registered domain.

**Permission:** `domains:write`

**Parameters:**

| Name       | Type          | Required | Description                          |
| ---------- | ------------- | -------- | ------------------------------------ |
| `domainId` | string (UUID) | Yes      | The domain the DNS record belongs to |
| `recordId` | string        | Yes      | The DNS record ID to delete          |

**Returns:** `{ "success": true, "recordId": "..." }`

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Contact Tools" icon="address-book" href="/mcp-server/tools/contacts">
    Manage CRM contacts, distinct from the WHOIS-style domain contacts above
  </Card>

  <Card title="Authentication" icon="key" href="/mcp-server/authentication">
    Learn how MCP clients authenticate to the server
  </Card>
</CardGroup>
