Namecheap MCP connects your AI assistant (such as Claude) to your Namecheap account. Through it, the assistant can check and register domains, hand you a link to buy a domain on Namecheap's own site instead, manage domain contacts, and read or edit DNS records on your behalf — you just ask in plain language, and the assistant calls the right tools.
You need a Namecheap account. Namecheap MCP is available at https://mcp.namecheap.com/mcp.
How you connect depends on your AI assistant:
https://mcp.namecheap.com/mcp. Anthropic's Claude is the client we have verified this to work with.https://mcp.namecheap.com/mcp. Other clients may work, but we haven't verified them yet.When you connect, you'll be asked to sign in to Namecheap and grant the assistant access to your account. Which tools the assistant can use depends on the access you approve — if a tool is rejected because access wasn't granted, reconnect and approve the access it needs.
The agreements and policies that apply to Namecheap MCP and to anything you buy through it:
Namecheap registrations complete synchronously, so there is no background-operation tool to poll. domain_register buys a domain in the conversation, paid with a saved payment method or Namecheap account funds, and is the preferred way to buy. domain_purchase_link returns a link the customer opens and pays on themselves, choosing their own payment method on namecheap.com, and domains_list is what confirms the outcome afterwards.
| Tool | What it does |
|---|---|
contacts_save
|
Save contact details and get a contact ID |
contacts_get
|
Read a saved contact by its ID |
contacts_list
|
List all saved contacts to find and reuse one |
domains_list
|
List your domains, or look up one domain |
domains_check_availability
|
Check if domains are available to register |
domain_register
|
Register (buy) a domain — spends money |
domain_purchase_link
|
Get a link for the customer to buy a domain on namecheap.com, paying their own way |
domain_set_contacts
|
Assign contacts to a domain you own |
domain_set_nameservers
|
Switch a domain to basic or custom nameservers |
dns_records_get
|
Read DNS records for a domain |
dns_records_save
|
Add DNS records or update their TTL |
dns_records_delete
|
Delete DNS records |
Wherever a contact is required (domain_register, domain_set_contacts), each role accepts either:
firstName, lastName, email, …). It is saved to your Namecheap account automatically; you do not have to call contacts_save first.{ "contactId": "…" } pointing at a contact you saved earlier with contacts_save, or one you found with contacts_list.A contactId is an opaque string (1–32 characters). Do not parse it or assume a format — just pass it back where a contact is accepted. You may also reuse a contactId from a contacts_list result, so look up the contacts already saved on your account before entering new details.
Several tools are designed to be used together: the output of one becomes the input of the next.
domain_register is the preferred way to buy a domain: it registers the name inside the conversation and charges the customer's default saved payment method, or Namecheap account funds when there is no usable default, after an explicit confirmation step. The customer can pick any other saved method or account funds instead. On a purchase request, use it — don't ask the customer to choose between it and the purchase link. To let the customer check out on namecheap.com themselves, see Buying through the purchase link below.
domains_check_availability
— check the name(s) you want. Only proceed when result is available. Each available name includes the USD price to register it (standard and premium alike), or priceUnavailableReason when it can't be determined, plus minRegisterPeriodInYears and maxRegisterPeriodInYears — the term that TLD allows. Note the price covers price.pricedYears years, which is the TLD's shortest allowed term and is not always 1.domain_register
(preview) — call with confirmationToken unset to get status: confirmation_required, a fresh confirmationToken, and the price that will be charged. Nothing is billed. Omit paymentMethodId to let the tool propose the account's default payment method (or account funds when there is no usable default) — the response then also carries paymentMethods so a different one can be chosen; pass a specific id as paymentMethodId to charge that method instead. The tool's response text is a full confirmation — term, price breakdown, auto-renew, WHOIS privacy, payment source, and the registrant/admin/tech/billing contacts — show it to the user as-is. Pick years between minRegisterPeriodInYears and maxRegisterPeriodInYears from step 1 — an out-of-range value is rejected outright. Contacts can be passed inline here, or as { contactId } if you saved them with contacts_save. Before entering new details, look up the account's saved contacts with contacts_list and reuse one by its contactId.domain_register
(accept/decline) — after the user agrees, call again with the exact same arguments plus that confirmationToken and confirmationResponse: "accept". This charges the resolved payment method and is irreversible. It returns the outcome directly (no polling): usually status: completed with the amount charged, or status: pending while the registry finishes. To cancel instead, call again with the same confirmationToken and confirmationResponse: "decline" — nothing is billed. If the price can't be determined on either call, the tool returns status: price_unavailable instead and nothing is charged. If no payment method can be used, it returns status: payment_unavailable with the account's saved methods and nothing is charged.domains_list
— if the result was pending, call domains_list for the domain shortly to confirm it is registered.domains_check_availability --> domain_register --> domain_register --> (domains_list if pending)
(available? + price + (token unset: (token + accept: confirm final state
min/maxRegisterPeriod) confirmation, completed/pending)
confirmationToken,
no charge)
domain_purchase_link hands the customer a link to Namecheap's own consent and payment page, where they approve and pay themselves. Because they pick their payment method there, it is the route when the customer wants to check out on namecheap.com themselves rather than in the conversation — for example after a domain_register result of payment_unavailable that asks them to complete the purchase on the website — or when the customer or the client simply asks for a link. The consent page has no field for term, WHOIS privacy or contacts, so none of those can be set this way.
Never hand out the link when a purchase attempt's outcome is unknown. A domain_register result whose note says the outcome is unknown means the registration may have completed and billed. A purchase link there risks charging the customer a second time for a domain they already bought. Call domains_list for the domain first, and offer the link only if it is genuinely not registered.
domains_check_availability --> domain_purchase_link --> (domains_list to confirm)
(available? + price) (consentUrl the customer after the customer says
opens and pays on they've completed checkout
namecheap.com; no charge
from this call)
contacts_list
— look up the contacts already saved on the account and pick one to reuse (optional — inline details work too).domain_set_contacts
— assign contacts to the domain, inline or by { contactId }, reusing a contactId from contacts_list where one fits. Completes immediately. verificationStatus is always null for Namecheap. Some TLD registries require extended attributes — pass them via tldAttributes.domains_list
— find the domain and see its current nameservers ({ provider, hosts }; populated when fetching a single domain).domain_set_nameservers
— switch it to Namecheap's default nameservers with provider: "basic" (no hosts), or point it at your own with provider: "custom" and a list of 2–12 hosts. It returns the resulting { provider, hosts }. Re-applying the state a domain is already in returns a validation error rather than a no-op — treat that as expected, not a failure to retry.domains_list
— find the domain you want to manage (or pass its name directly if you know it).dns_records_get
— read the current records for the domain.dns_records_save
or dns_records_delete — add, update, or remove records. Records returned by dns_records_get have the same shape the save and delete tools accept (delete just omits ttl), so the assistant can read, adjust, and write back. Matching is case-insensitive except for TXT records, which are case-sensitive.domains_list
— page through all your domains with sorting, or fetch a single domain by name. See the tool below for which fields Namecheap reports.contacts_list
— page through all the contacts saved on your account to find and reuse an existing one (by its contact ID) instead of creating a duplicate.contacts_get
— look up the details behind any contact ID you see on a domain or in a contacts_list result.Every tool returns its result as structured JSON, and every tool completes immediately — Namecheap has no long-running background operations.
Contacts are the people or organizations attached to a domain registration (registrant, admin, tech, billing). A contact is referenced everywhere by its contact ID — an opaque string.
contacts_save — Save ContactSaves contact details and returns the generated contact ID. Validation of some fields (such as stateProvince and postalCode) depends on the selected country.
Idempotent. Saving details identical to a contact you saved before reuses that existing contact ID instead of creating a duplicate.
| Parameter | Required | Type & constraints |
|---|---|---|
firstName
|
Yes | String, 1–64 chars. May include hyphens and apostrophes. |
lastName
|
Yes | String, 1–64 chars. May include hyphens and apostrophes. |
email
|
Yes | Valid email address, max 254 chars. |
address1
|
Yes | Address line 1. String, 1–128 chars. |
city
|
Yes | String, 1–64 chars. |
country
|
Yes | Two-letter country code (ISO 3166-1 alpha-2), e.g. US. |
phone
|
Yes | International format +CountryCode.Number, e.g. +1.2025551234. Max 32 chars. |
organization
|
No | Organization/company name. 1–128 chars. |
address2
|
No | Address line 2. 1–128 chars. |
stateProvince
|
No | State/province name, 1–64 chars. May be required depending on the country. |
postalCode
|
No | 1–16 chars. May be required depending on the country. |
phoneExt
|
No | Phone extension, 1–16 chars. |
fax
|
No | Fax number, same +CountryCode.Number format, max 32 chars. |
taxNumber
|
No | Tax number, 1–32 chars. |
Returns
{ "contactId": "..." }
contactId (opaque, 1–32 chars) is what you pass to domain_register, domain_set_contacts, and contacts_get; contacts_list returns the ids of everything you have saved.
When Namecheap's address validation proposes a corrected address, the result may additionally include an addressSuggestion:
{
"contactId": "...",
"addressSuggestion": {
"status": "corrected",
"suggestedAddress": {
"address1": "...", "address2": "...", "city": "...",
"stateProvince": "...", "country": "...", "postalCode": "..."
}
}
}
Each field of suggestedAddress is present only when Namecheap proposes a value for it. Treat it as a suggestion to show the user, not an automatic change — the contact is still saved with the details you submitted.
contacts_get — Get ContactReads the details of a saved contact by its contact ID. Contact IDs come from contacts_save or a contacts_list result.
| Parameter | Required | Type & constraints |
|---|---|---|
contactId
|
Yes | Opaque contact ID, 1–32 chars. |
Returns — { contact } with:
| Field | Type |
|---|---|
firstName, lastName, email, address1, city, country, phone, postalCode |
String |
organization, address2, stateProvince, phoneExt, fax, faxExt, taxNumber |
String or null |
contacts_list — List ContactsLists all contacts saved under your account, so you can find and reuse an existing contact (by its contact ID) instead of creating a duplicate. The list is paginated and sortable, consistent with domains_list.
| Parameter | Required | Type & constraints |
|---|---|---|
take
|
No | Items per page, 1–100. Default 10. |
skip
|
No | Items to skip, 0 or more. Default 0. |
orderBy
|
No | Up to 8 sort keys: name, email, organization; prefix with - for descending (e.g. -name). Without orderBy, contacts come back in the order your account stores them. |
Returns — { items, total } where total is the number of contacts saved on the account (not the page size), and each item carries enough to tell contacts apart without a follow-up call:
| Field | Type |
|---|---|
contactId
|
String (opaque). Pass to contacts_get, domain_set_contacts, or domain_register. |
name
|
String — the contact's name. |
email
|
String or null when the contact has no email on record. |
organization
|
String or null when the contact has no organization on record. |
{
"items": [
{ "contactId": "424242", "name": "Ada Lovelace", "email": "ada@example.com", "organization": "Analytical Engines" }
],
"total": 1
}
Domain name inputs (domain/domainName) accept Unicode (IDN) or ASCII (A-label) — either way, the tool normalizes the name to punycode automatically before use. domains_check_availability and domain_register additionally require a TLD Namecheap supports for registration: a domain whose TLD isn't supported is treated as not available rather than checked or charged. The other domain tools (domains_list, domain_purchase_link, domain_set_contacts, domain_set_nameservers) and the DNS tools normalize the name only and never reject on TLD support.
domains_list — List DomainsRetrieves a paginated list of your domains. Pass domain to fetch a single domain by name instead (pagination and ordering are then ignored, and the result includes a note saying so if they were supplied).
| Parameter | Required | Type & constraints |
|---|---|---|
domain
|
No | Fully qualified domain name to fetch a single domain. Accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
take
|
No | Items per page, 1–100. Default 10. |
skip
|
No | Items to skip, 0 or more. Default 0. |
orderBy
|
No | One sort key: name, unicodeName, registrationDate, or expirationDate; prefix with - for descending (e.g. -expirationDate). |
Returns — { items, total } where each item describes a domain:
| Field | Meaning |
|---|---|
name / unicodeName |
Domain name. Namecheap reports unicodeName as a mirror of name (no distinct Unicode form). |
isPremium
|
Whether the domain is a premium name. |
autoRenew
|
Whether auto-renew is enabled — see the note below on when this is reported. |
registrationDate / expirationDate |
Registration and expiration timestamps. |
lifecycleStatus
|
creating, registered, grace1, or redemption. |
verificationStatus
|
Not reported by Namecheap — always null. |
eppStatuses
|
Not reported by Namecheap — empty. |
suspensions
|
Not reported by Namecheap — empty. |
privacyProtection
|
{ level: "public" | "high", contactForm: boolean }. |
nameservers
|
{ provider: "basic" | "custom", hosts: [...] }. See the note below. |
contacts
|
Not reported by Namecheap — comes back empty. Use contacts_list to find your saved contacts, or contacts_get if you already hold a contact ID. |
contactDetails
|
Present only when fetching a single domain via domain: the full contact details assigned to the domain, per role (registrant, admin, tech, billing). See the note below. |
Namecheap-specific reporting:
contacts, eppStatuses, suspensions, and verificationStatus are not reported — they come back empty or null.unicodeName always mirrors name.nameservers is populated only when fetching a single domain via domain. In the multi-item list it reports the basic default with no hosts.contactDetails is populated only when fetching a single domain via domain. It carries the actual registrant/admin/tech/billing contact details assigned to that domain, so you can read them without holding a contact ID. The id-based contacts field still comes back empty even in the single-domain case, and contactDetails is not included in the multi-item list.autoRenew is a real true/false only in the multi-item list. Fetching a single domain via domain returns autoRenew: null, because Namecheap's single-domain lookup carries no auto-renew field — reported as null rather than a misleading false.domains_check_availability — Check Domain AvailabilityChecks whether one or more domain names are available to register. Uses the single-domain endpoint for one name and the bulk endpoint for multiple. A domain whose TLD isn't supported for registration is not sent to the availability check at all — it's returned immediately as tldNotSupported.
| Parameter | Required | Type & constraints |
|---|---|---|
domains
|
Yes | 1–20 fully qualified domain names. Each accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
Returns — { results }, one entry per requested name:
| Field | Meaning |
|---|---|
domain
|
The checked name. |
result
|
available, taken, invalidDomainName, tldNotSupported, or unexpectedError. |
premiumPricing
|
For premium names: list of { operation, price, currency } where operation is register, transfer, renew, or restore. Empty for regular names. |
price
|
For available names (standard and premium): the USD price to register the domain for the shortest term the TLD allows — { amount, currency: "USD", pricedYears?, pricePerYear?, icannFee?, isPremium }. amount is the payable total for that whole term; pricedYears states how many years it covers. No pre-discount or "was" price is reported. icannFee is the ICANN fee (USD) already included in amount, returned separately so the breakdown can be explained; it appears only when the TLD carries a fee. |
pricePerYear
|
Inside price: amount divided by pricedYears, so a yearly figure is always available for comparison. When pricedYears is 1 it is the real one-year price; above that it is a per-year average of the term, not a term you could buy. Omitted for premium names, whose quote carries no term. |
minRegisterPeriodInYears / maxRegisterPeriodInYears |
For available names: the shortest and longest registration period that TLD actually permits, as two plain numbers. Use them to pick a valid years for domain_register. Both omitted when the allowed period could not be determined. |
priceUnavailableReason
|
Present instead of price when the price could not be determined for an available name. The check itself still succeeds. |
Only available names are priced; taken/invalid results carry neither price nor priceUnavailableReason.
Most TLDs allow one year, but some do not. .ai, for example, has a two-year minimum. For those, price.amount is the total for the minimum term — not a one-year price you could act on — and price.pricedYears says so:
{
"domain": "example.ai",
"result": "available",
"premiumPricing": [],
"price": { "amount": 79.98, "currency": "USD", "pricedYears": 2, "pricePerYear": 39.99, "isPremium": false },
"minRegisterPeriodInYears": 2,
"maxRegisterPeriodInYears": 10
}
pricePerYear is present here — 79.98 divided by the two years it covers gives 39.99. This is the total divided by the term, not a price you could pay for a single year (a one-year .ai registration cannot be bought). Always show amount together with pricedYears ("$79.98 for 2 years"), never amount alone. For an ordinary TLD, pricedYears is 1 and pricePerYear equals amount.
Namecheap-specific reporting
minRegisterPeriodInYears/maxRegisterPeriodInYears come from Namecheap's own TLD catalogue. Where that catalogue understates a minimum, the gateway corrects it from what the pricing service will actually sell: the first affected request may report the catalogue's value, and every request after it reports the corrected one.pricePerYear is never reported for a premium name — a premium quote carries no term, so a per-year figure would be invented.domain_register — Register DomainRegisters (buys) a domain. This charges a payment method — your default saved method, account funds, or one you choose — and is irreversible. This is the preferred way to buy a domain — on a purchase request use this tool rather than offering the customer a choice of purchase paths. Recommended sequence: domains_check_availability -> domain_register. A domain whose TLD isn't supported for registration is rejected immediately — before any availability check, pricing, or charge.
years must be within the TLD's own allowed period. The 1–10 bound below is the outer limit across all TLDs; each TLD is narrower. .ai allows 2–10, .co and .io allow 1–5, .sg 1–2, .fr exactly 1. A years outside that range is rejected with a validation error naming the allowed range — before any availability check, pricing or charge — and the value is not quietly adjusted for you:
.ai domains cannot be registered for 1 year: this TLD allows 2–10 years. Call domains_check_availability for this domain to see its allowed registration period.
Read minRegisterPeriodInYears/maxRegisterPeriodInYears from domains_check_availability first and pick a years inside it. The same check re-runs on the confirming (confirmationResponse: "accept") call, so it can never be bypassed by confirming.
Contacts. Each contact role takes inline details or a { contactId } reference. You may also reuse a contactId from a contacts_list result, so look up the contacts already saved on the account and reuse one before entering new details.
Two-step pre-charge confirmation. Call first with confirmationToken unset: the tool prices the domain fresh, resolves the payment method, builds a full confirmation — term, price breakdown (including any ICANN fee and whether the domain is premium), auto-renew, WHOIS privacy, payment source, and the registrant/admin/tech/billing contacts (a contact identical to the registrant is shown as "same as registrant") — and returns status: "confirmation_required" with that price and a fresh confirmationToken. Nothing is registered or billed on this call. The full confirmation is the tool's response text; show it to the user as-is. Once they agree, call again with the exact same arguments plus this confirmationToken and confirmationResponse: "accept" to submit the purchase, or confirmationResponse: "decline" to cancel it — nothing is billed on a decline. The token is bound to these exact arguments, the quoted price, and the resolved payment method, and expires after a short time: a missing, expired, tampered, or no-longer-matching token on the confirming call simply returns a brand-new confirmation with a fresh token — never an error, never a charge. If the price cannot be determined on either call, the tool returns status: "price_unavailable" instead of a token and never charges; retry later.
Choosing a payment method. Omit paymentMethodId to charge the account's default saved payment method, or account funds when there is no usable default — the confirmation names the resolved source in paymentSource and its response text, and account funds are only chosen when the balance, in the price's currency, covers the price. When it's omitted, the response also carries paymentMethods: the account's saved cards and account funds with its balance, each with an id and a display label (e.g. "Visa ···1234" or "Account funds (USD 17.29)"), so the customer can pick a different one — pass that id back as paymentMethodId on the next call to charge it instead. A requested id that isn't on the account, an expired method, or one that can't be charged for this purchase (e.g. flagged as not usable for an unattended charge), is rejected with a validation error naming the reason — no token is minted and nothing is charged. If no payment method can be used at all — no saved method is usable and account funds don't cover the price, or the saved methods couldn't be read — the tool returns status: "payment_unavailable" with the reason and the account's saved methods, and never charges; the customer needs to choose another method, add one, or add funds. Adding, editing or removing payment methods is not something this tool does — the customer manages them in their Namecheap account.
Synchronous. Unlike some registrars, Namecheap registration completes as part of the call — there is no operation to poll. A confirmed call returns its outcome directly (see the status table below).
| Parameter | Required | Type & constraints |
|---|---|---|
domain
|
Yes | Fully qualified domain name to register, e.g. example.com. Accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
years
|
Yes | Registration period in years. 1–10 is the outer bound; the accepted range is the TLD's own — see minRegisterPeriodInYears/maxRegisterPeriodInYears from domains_check_availability. Out-of-range values are rejected, not adjusted. |
autoRenew
|
Yes | Boolean. When true, the domain renews automatically at expiration using the account's default payment method. Auto-renew is turned on right after the domain is registered and charged, and is reported separately in the result (see below). |
privacy.level
|
Yes |
high hides the registrant's contact details from public WHOIS; public publishes them. |
privacy.userConsent
|
Yes | Boolean. Must confirm you agree to the selected privacy setting. |
contacts.registrant
|
Yes | Inline contact details or { contactId } (an id from contacts_save or contacts_list). |
contacts.admin
|
Yes | Inline contact details or { contactId } (an id from contacts_save or contacts_list). |
contacts.tech
|
Yes | Inline contact details or { contactId } (an id from contacts_save or contacts_list). |
contacts.billing
|
Yes | Inline contact details or { contactId } (an id from contacts_save or contacts_list). |
tldAttributes
|
No | Extended attribute values keyed by name, required only for certain TLDs (e.g. registrant nexus or legal-type fields). Provide them for TLDs that need them; omit otherwise. |
paymentMethodId
|
No | String, 1–64 chars. Id of a saved payment method to charge, taken from a previous call's paymentMethods list. Omit to accept the account's default payment method (or account funds when there is no usable default). |
confirmationToken
|
No | String, up to 4096 chars. Server-issued token returned by a previous domain_register call for these exact arguments. Omit on the first call for a new registration attempt. Expires after a short time and is bound to the exact arguments, price, and payment method it was issued for — resend it unchanged, together with confirmationResponse, to act on it. |
confirmationResponse
|
Conditional |
"accept" or "decline". Only meaningful together with a valid confirmationToken. "accept" submits the (billed) registration shown in that confirmation; "decline" cancels it without charging. Omit on the first call. |
Returns — after the first call (nothing charged):
{
"domain": "example.com",
"years": 1,
"status": "confirmation_required",
"price": {
"amount": 9.08,
"currency": "USD",
"pricedYears": 1,
"pricePerYear": 9.08,
"icannFee": 0.2,
"isPremium": false
},
"confirmationToken": "<opaque confirmation token>",
"paymentSource": "Visa ···1234",
"note": "Nothing has been charged yet. Show the confirmation to the user and, once they agree, call domain_register again with this confirmationToken and confirmationResponse=\"accept\" to complete the purchase, or confirmationResponse=\"decline\" to cancel."
}
Returns — after the first call with paymentMethodId omitted, additionally carrying the account's payment methods so the customer can pick a different one:
{
"domain": "example.com",
"years": 1,
"status": "confirmation_required",
"price": {
"amount": 9.08,
"currency": "USD",
"pricedYears": 1,
"pricePerYear": 9.08,
"icannFee": 0.2,
"isPremium": false
},
"confirmationToken": "<opaque confirmation token>",
"paymentSource": "Visa ···1234",
"paymentMethods": [
{ "id": "3f2a9c1e-7b64-4d0a-9e51-2c8f6a1b0d47", "type": "Funds", "order": 0, "label": "Account funds (USD 17.29)", "availableBalance": 17.29, "balanceCurrency": "USD" },
{ "id": "a81c5e02-94d3-4f7b-b6a0-13e9d2c47f58", "type": "CreditCard", "order": 1, "label": "Visa ···1234" }
],
"note": "Nothing has been charged yet. Show the confirmation to the user and, once they agree, call domain_register again with this confirmationToken and confirmationResponse=\"accept\" to complete the purchase, or confirmationResponse=\"decline\" to cancel."
}
Alongside this JSON, the tool's response text is the full confirmation to show the user — it restates the domain, term, and price above, plus lines for Auto-renew: on/off, WHOIS privacy: on/off, Payment source: <resolved method label>, and each of the registrant/admin/tech/billing contacts (name, email, country — a contact matching the registrant reads "same as registrant"), followed by instructions for the next call. A paymentMethods entry never carries card numbers, cardholder names, or any billing or issuer detail beyond label — isExpired (present whenever a card's expiry could be read) and offSessionForbidden (present only when true) flag a method as not currently usable when true, and availableBalance/balanceCurrency are present only for the account funds entry. For a multi-year term, price.amount is the total for the whole term and price.pricePerYear is that total divided by the term — e.g. years: 5 on .com returns { "amount": 71.40, "pricedYears": 5, "pricePerYear": 14.28 }, and example.ai with years: 2 returns { "amount": 79.98, "pricedYears": 2, "pricePerYear": 39.99 }.
Returns — after confirmationResponse: "accept" (registered and charged):
{
"domain": "example.com",
"years": 1,
"status": "completed",
"charged": { "amount": 9.08 },
"operation": { "kind": "order", "id": 123456 },
"price": {
"amount": 9.08,
"currency": "USD",
"pricedYears": 1,
"pricePerYear": 9.08,
"icannFee": 0.2,
"isPremium": false
},
"note": "..."
}
Returns — after confirmationResponse: "decline" (nothing charged):
{
"domain": "example.com",
"years": 1,
"status": "cancelled",
"price": { "amount": 9.08, "currency": "USD", "pricedYears": 1, "pricePerYear": 9.08, "icannFee": 0.2, "isPremium": false },
"note": "Registration of example.com was not submitted because the purchase was not confirmed."
}
Returns — if the price can't be determined, on either call:
{
"domain": "example.com",
"years": 1,
"status": "price_unavailable",
"priceUnavailableReason": "Price is currently unavailable for this domain.",
"note": "Registration of example.com could not be priced right now, so nothing was confirmed or charged. Try again shortly."
}
Returns — if no payment method can be used, on either call:
{
"domain": "example.com",
"years": 1,
"status": "payment_unavailable",
"price": {
"amount": 9.08,
"currency": "USD",
"pricedYears": 1,
"pricePerYear": 9.08,
"icannFee": 0.2,
"isPremium": false
},
"paymentMethods": [
{ "id": "3f2a9c1e-7b64-4d0a-9e51-2c8f6a1b0d47", "type": "Funds", "order": 0, "label": "Account funds (USD 4.10)", "availableBalance": 4.1, "balanceCurrency": "USD" },
{ "id": "a81c5e02-94d3-4f7b-b6a0-13e9d2c47f58", "type": "CreditCard", "order": 1, "label": "Visa ···1234", "isExpired": true }
],
"note": "example.com was not registered and nothing was charged. Your account funds (USD 4.10) do not cover the USD 9.08 price. Add funds to the account or choose a saved payment method."
}
Charge refused for a payment reason. The same payment_unavailable status is returned, still with nothing charged and no token, when the charge itself is refused for a recognised payment reason after the customer accepted. The note carries fixed guidance for the cause, and paymentMethods lists the account's methods again when they can be read:
| Cause | What the note tells the customer |
|---|---|
| The selected method is not available for this purchase | Choose another payment method or use account funds. |
| The selected card has expired | Choose another payment method or use account funds. |
| Card payments are not supported for this domain extension | Use account funds or another payment method. |
| The payment method could not be verified (temporary) | Try again in a few minutes, or choose another payment method. |
| Account funds do not cover the price | Add funds to the account or choose a saved payment method. |
| The card was declined | Choose another payment method, or complete the purchase on the Namecheap website. |
| The card was declined because it does not have enough funds | Use another payment method or account funds, or complete the purchase on the Namecheap website. |
| The card provider rejected the card details | Update the card on the Namecheap website or choose another payment method. |
| The card is not supported for this purchase | Choose another payment method or use account funds. |
| The card provider could not process the charge | Try again in a few minutes, or choose another payment method. |
| The card needs cardholder confirmation (such as 3-D Secure), which cannot be completed here | Choose another payment method, or complete the purchase on the Namecheap website. |
| The card could not be charged (any charge taken is refunded automatically) | Choose another payment method, or complete the purchase on the Namecheap website. |
Registration refused for a reason that is not payment. These keep status: "failed", with nothing charged and no token, and the note names what to fix:
| Cause | What the note tells the customer |
|---|---|
| A contact field is missing (for example the registrant state or province) | The <role> contact <field> is missing. Update the contact and try again. |
| A contact field is not valid | The <role> contact <field> is not valid. Update the contact and try again. |
| The price changed since it was quoted | Call domain_register again without the confirmation token to get a new quote. |
| The extension or term cannot be bought through this channel | Complete the purchase on the Namecheap website. |
| The order could not be created (any card charge is refunded automatically) | Try again, or complete the purchase on the Namecheap website. |
Any other refusal keeps status: "failed" with a generic note that the registration was not completed — the outcome of a failure the gateway does not recognise is never guessed.
status can be:
| Status | Meaning |
|---|---|
confirmation_required
|
Preview — nothing charged. Show the response text to the user, then call again with this confirmationToken and confirmationResponse. Also returned, with a new token, when a submitted confirmationToken is missing, expired, tampered, or no longer matches the current arguments/price/payment method — never an error. |
cancelled
|
The purchase was declined (confirmationResponse: "decline"), so nothing was submitted. |
completed
|
Registered and charged. Includes charged: { amount } and an operation order receipt. |
pending
|
Submitted; the registry is still finishing. Call domains_list shortly to confirm the final state. |
price_unavailable
|
The price could not be determined, so no token was issued and nothing was billed. Retry later. |
payment_unavailable
|
No usable payment method exists for this purchase — no saved method can be charged and account funds don't cover the price (or the saved methods couldn't be read) — or the charge was refused for a recognised payment reason. Nothing was billed. The note states the actual cause when the customer can act on it — the funds balance against the price, a funds currency that cannot pay the price, a wallet with nothing chargeable, or the refused charge's reason — and stays generic only when the saved methods could not be read; paymentMethods lists the account's methods so they can choose, add a method, or add funds. |
failed
|
The registration did not complete. If a network/timeout error interrupted the request, the note says the outcome is unknown and asks you to verify before retrying — the charge may or may not have gone through, so do not blindly resubmit, and do not offer domain_purchase_link either until domains_list shows the domain is not registered. |
operation here is { kind: "order", id } — an order receipt, not something to poll. The price shown at confirmation_required is exactly what will be charged on confirmationResponse: "accept" — price.amount is the total for that whole term and price.pricedYears states the term, so always show the two together. When the TLD carries an ICANN fee, price.amount already includes it and price.icannFee states the fee amount so it can be explained.
Auto-renew reporting: when autoRenew: true is requested, auto-renew is turned on right after the domain is registered and charged, as its own step. A completed registration therefore carries an additive autoRenew: { requested: true, applied }. If that separate call fails, the result still reports status: "completed" with charged set (the domain is registered and paid for) but autoRenew.applied is false, and the note explains that auto-renew did not apply and how to turn it on:
{
"domain": "example.com",
"years": 1,
"status": "completed",
"charged": { "amount": 9.08 },
"operation": { "kind": "order", "id": 123456 },
"autoRenew": { "requested": true, "applied": false },
"price": { "amount": 9.08, "currency": "USD", "pricedYears": 1, "pricePerYear": 9.08, "icannFee": 0.2, "isPremium": false },
"note": "example.com was registered successfully. Auto-renew was requested but could not be turned on after the charge — the domain is registered and the charge has completed. Enable auto-renew again, or check its current state via domains_list."
}
autoRenew is omitted entirely when it wasn't requested (autoRenew: false on the call).
When the customer would rather check out on namecheap.com — or a payment_unavailable note asks them to complete the purchase on the website — domain_purchase_link hands them a link to pay there with a payment method they pick — see Buying through the purchase link. Never offer that link on a failed result whose outcome is unknown without checking domains_list first.
domain_purchase_link — Get Domain Purchase LinkHands the customer a link to buy a domain on Namecheap's own consent and payment page, instead of charging the account from the conversation. This call charges nothing and registers nothing — it only creates the purchase link.
The customer approves and pays on namecheap.com, choosing their own payment method there. Never offer it to recover from a purchase whose outcome is unknown — check domains_list first, or the customer can be charged twice. See Buying through the purchase link.
Takes domain and an optional autoRenew. The consent page has no field for term length, WHOIS privacy, or contacts, so none of those can be set through this tool.
| Parameter | Required | Type & constraints |
|---|---|---|
domain
|
Yes | String. Fully-qualified domain name the customer agreed to buy, e.g. "example.com". Accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
autoRenew
|
No | Boolean. Whether the domain and its WHOIS privacy should renew automatically, charging the customer again each term. Defaults to on when omitted. The consent page shows this to the customer but does not let them change it there — they can change it afterwards in their account. |
Returns — the customer needs to open the link:
{
"domain": "example.com",
"status": "consent_required",
"consentUrl": "https://www.namecheap.com/apps/consent/1ec9218b-7766-49c8-b25f-a5cff1840746",
"expiresInSeconds": 1200,
"autoRenew": true,
"note": "To buy example.com, open this link and complete the checkout on Namecheap's site: https://www.namecheap.com/apps/consent/1ec9218b-7766-49c8-b25f-a5cff1840746\n\nAfter paying, follow the link back to finish the purchase. Nothing has been charged yet. The domain and its WHOIS privacy will renew automatically, charging the customer again each term. The consent page shows this but does not let the customer change it there — they can change it afterwards in their Namecheap account."
}
Returns — the domain cannot be bought right now:
{
"domain": "example.com",
"status": "unavailable",
"note": "example.com is not available to purchase right now. Check availability again before retrying."
}
status can be:
| Status | Meaning |
|---|---|
consent_required
|
The link was created. consentUrl is what the customer must open; expiresInSeconds is how long it stays valid. Nothing charged. |
unavailable
|
The domain is not available to purchase. This is a normal result, not an error. |
Namecheap-specific reporting: the customer approves and pays entirely on namecheap.com, and there is no follow-up call for you to make. However, the purchase is only completed once the customer follows the link back after paying — that return is what commits it. If the customer never returns, the purchase can be reverted and any amount charged is refunded automatically. So do not tell the customer the domain is theirs on the strength of this call: confirm with domains_list first. The link is single-use — reopening it after a completed purchase may report a failure even though the domain was bought, so domains_list is the authority on the outcome.
domain_set_contacts — Set Domain ContactsChanges the contacts assigned to a domain you own. Completes immediately. You may also reuse a contactId from a contacts_list result, so look up the contacts already saved on the account and reuse one before entering new details.
| Parameter | Required | Type & constraints |
|---|---|---|
domainName
|
Yes | Fully qualified domain name. Accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
registrant
|
Yes | Inline contact details or { contactId }. |
admin
|
No | Inline contact details, { contactId }, or null. |
tech
|
No | Inline contact details, { contactId }, or null. |
billing
|
No | Inline contact details, { contactId }, or null. |
tldAttributes
|
No | Extended attribute values keyed by name, for TLDs that require them. |
Returns
{ "verificationStatus": null }
Namecheap does not report an RAA verification state, so verificationStatus is always null.
domain_set_nameservers — Set Domain NameserversChanges a domain's registrar-level nameservers. Completes immediately. The change is reflected by domains_list (single-domain fetch) afterwards.
| Parameter | Required | Type & constraints |
|---|---|---|
domainName
|
Yes | Fully qualified domain name. Accepts Unicode (IDN) or ASCII (A-label) — normalized to punycode automatically. |
provider
|
Yes |
basic (Namecheap's default nameservers) or custom (your own hosts). |
hosts
|
Conditional | Required when provider is custom: 2–12 nameserver hostnames (each a valid FQDN, 4–255 chars). Must be omitted when provider is basic. |
Returns
{ "provider": "custom", "hosts": ["ns1.example.com", "ns2.example.com"] }
Re-applying the state a domain is already in (e.g. setting basic when it is already basic) returns a validation error rather than a no-op success — treat that as an expected result, not a failure to retry.
The domainName these tools take accepts Unicode (IDN) or ASCII (A-label) and is normalized to punycode automatically; TLD support is not enforced here.
dns_records_get — Get DNS RecordsRetrieves a paginated list of DNS resource records for a domain.
| Parameter | Required | Type & constraints |
|---|---|---|
domainName
|
Yes | The domain whose records to fetch. |
take
|
No | Items per page, 1–500. Default 100. |
skip
|
No | Items to skip, 0 or more. Default 0. |
orderBy
|
No | Up to 8 sort keys: type, -type, name, -name. |
Returns — { items, total }, plus omittedRecords when the zone contains records this tool cannot return (see below). Each item is a record as described in Record shapes, plus an optional group field indicating where the record comes from (custom — created by you, product — managed by a product, personalNs — personal nameservers).
Namecheap-specific: a record that cannot be represented in the typed contract is omitted from items. Two kinds are omitted: record types outside the contract — the URL, FRAME and URL301 redirect records Namecheap stores in the zone (a parked domain normally has one) — and malformed CAA/TLSA/HTTPS/SVCB values. total still counts every record in the zone, including the omitted ones, so total can be larger than the number of records you can page through. Every omitted record is listed in omittedRecords by type and name, so nothing is dropped without being reported; the field is absent when nothing was omitted. Manage omitted records in the Namecheap dashboard.
{
"items": [
{ "type": "CNAME", "name": "www", "cname": "parkingpage.namecheap.com.", "ttl": 1800 }
],
"total": 2,
"omittedRecords": [
{ "type": "URL", "name": "@" }
]
}
dns_records_save — Save DNS RecordsAdds custom DNS records or updates the TTL of existing ones. Records are matched case-insensitively, except TXT records (case-sensitive).
| Parameter | Required | Type & constraints |
|---|---|---|
domainName
|
Yes | The domain whose records to update. |
records
|
Yes | 1–500 records — see Record shapes. Each may include an optional ttl. |
force
|
No | Boolean. Skips the conflict-resolution check and forces the zone update. |
Returns — { "saved": <number> }, the count of submitted records. Unless force is set, a successful response means every record was accepted and confirmed present in the zone; if any record fails, the whole call returns an error instead.
Namecheap-specific: after writing, the zone is re-read to confirm the records actually persisted. Namecheap can accept a record and then drop it — for example an MX record at @ on a domain with email forwarding enabled, whose mail records Namecheap manages itself. A record accepted but missing from that re-read is reported as a conflict naming the record, not counted as saved. force: true deliberately opts out of that protection: the call then reports success and saved counts the records as submitted, even if some were dropped, so only use it when you intend to bypass conflict handling. If the re-read itself cannot be completed, the call fails — with force set or not — with a message saying the write may have been applied but could not be confirmed; re-read the zone with dns_records_get before retrying, rather than repeating the write. SRV records are the one exception: if Namecheap cannot return SRV records during the re-read, they are reported as saved without being confirmed.
dns_records_delete — Delete DNS RecordsDeletes custom DNS records. Deletions cannot be undone. Records are matched case-insensitively, except TXT records (case-sensitive).
| Parameter | Required | Type & constraints |
|---|---|---|
domainName
|
Yes | The domain whose records to delete. |
records
|
Yes | 1–500 records identifying existing records — same shapes as save, but without ttl. |
Returns — { "deleted": <number> }, the count of submitted records. If any record cannot be matched, the whole call fails and nothing is deleted.
Every record has:
type — one of the 13 supported types below.name — the record name excluding the domain: use @ for the domain itself (apex) and * for a wildcard.ttl (save only, optional) — cache time in seconds, 60–3600.Type-specific fields:
| Type | Fields |
|---|---|
A
|
address — IPv4 address. |
AAAA
|
address — IPv6 address. |
CNAME
|
cname — canonical domain name (max 253 chars). |
ALIAS
|
aliasName — canonical domain name; CNAME-like behavior for the apex, where CNAME isn't allowed. |
NS
|
nameserver — nameserver name. |
PTR
|
pointer — domain name for the given IP address. |
TXT
|
value — text value (matched case-sensitively). |
MX
|
exchange — mail server; preference — priority (0–65535, lower preferred). |
CAA
|
flag — 0 or 128 (critical bit); tag — issue, issuewild, or iodef; value — CA identifier with optional parameters. |
SRV
|
service (e.g. _sip); protocol (e.g. _tcp); priority and weight (0–65535); port (1–65535); target — server domain name. |
TLSA
|
usage, selector, matching (each 0–255); port — * or _<1–65535>; protocol (e.g. _tcp); associationData — certificate hash or data. |
HTTPS
|
svcPriority (0–65535; 0 = AliasMode); targetName — FQDN or .; optional port (* or _<1–65535>), scheme (must be _https when port is set), svcParams. |
SVCB
|
svcPriority (0–65535; 0 = AliasMode); targetName — FQDN or .; optional port, scheme (e.g. _tcp), svcParams. |
CAA/TLSA/HTTPS/SVCB values is normalized into the fields above where possible. Values that don't fit the typed shape are readable in the zone but are omitted from dns_records_get's items and listed in its omittedRecords (see that tool). Standard records (A, AAAA, CNAME, MX, TXT, NS, etc.) are unaffected.CNAME, ALIAS, NS, PTR, the MX exchange, the SRV target) come back with a trailing dot, and a CAA value comes back quoted. You do not need to reproduce that when matching a record — dns_records_save and dns_records_delete accept either the value you originally submitted or the value dns_records_get reads back.When a call fails, the tool returns an error with a code and a human-readable detail explaining what went wrong — for example invalid input (a malformed domain name or contact ID), a domain or contact that doesn't exist, or a conflict with the current state. If a tool is rejected because the assistant wasn't granted access to it, reconnect Namecheap MCP and approve the access it asks for.
Need help? We're always here for you.