whydot

Three surfaces, one contract.

The API is the product. The CLI follows its operation table, and MCP exposes the operations an agent can perform. Steps that require a person are marked below. This page is generated from the operation table and the MCP policy.

Manual installation
curl -fsSL https://whydot.com/install.sh | sh then whydot login. The service describes itself at api.whydot.com/v1/openapi.json.

Authentication

One bearer token, issued by whydot login and stored by the CLI. It is shown once and never retrievable afterwards. There is no password and no web login form.

Authorization: Bearer wd_… Keys carry scopes, so a key that only reads cannot spend.

Spending money is explicit

Every call that can spend requires an idempotency key you choose. Send the same key twice and you get the first answer back, not a second domain and a second charge. The registrar's own API accepts no such token, so this is the only thing standing between a retry and a double purchase — which is why it is required rather than optional.

POST /v1/domains/:id/register with idempotencyKey. A 402 means the balance is short; top up and send the same key again.

Operations

RouteWhat it doesScope
POST /v1/tenants Create an account and its first API key. writes no key
GET /v1/keys List the API keys on this account, by prefix. keys:manage
POST /v1/keys Issue a new API key. writes keys:manage
DELETE /v1/keys/:id Revoke an API key immediately. writes keys:manage
GET /v1/domains List the domains in this account. domains:read
GET /v1/domains/:id Fetch one domain by id or by name. domains:read
POST /v1/domains Track a domain in this account. Spends nothing; registration is a separate call. writes domains:write
POST /v1/registrant-contacts Create a registrant contact for this account. writes domains:write
GET /v1/availability Is a domain available, and what would it cost. domains:read
GET /v1/prices Per-TLD registration prices. domains:read
POST /v1/domains/:id/register Register a tracked domain with the registrar. Spends money; requires an idempotency key. writes domains:write
GET /v1/domains/:id/dns The managed DNS records of a domain's zone, and what cannot be modelled. dns:read
POST /v1/domains/:id/dns/plan What would change if these records were the zone's whole contents. Writes nothing. dns:read
POST /v1/domains/:id/dns/apply Apply a plan from the plan route. Deleting needs allowDelete on THIS request. writes dns:write
POST /v1/dns-connections Connect the customer's own Cloudflare account. The token is proved, then sealed. writes dns:write
GET /v1/dns-connections The connected DNS provider accounts. Never the credentials. dns:read
POST /v1/dns-connections/:id/verify Ask the provider again whether the stored credential still works. writes dns:write
POST /v1/dns-connections/:id/archive Retire a connection. Refused while a live zone is served through it. writes dns:write
POST /v1/domains/:id/dns/zone Serve this domain's DNS through a connection. Creates the zone and reports the nameservers. writes dns:write
POST /v1/domains/:id/dns/zone/delegate Point the registrar at the serving zone's nameservers. Populate the zone first. writes dns:write
POST /v1/domains/:id/dns/zone/release Stop serving this domain's DNS through a connection. The zone at the provider is left alone. writes dns:write
GET /v1/domains/:id/dns/zone Where this domain's DNS is served, now and before. The serving row is first. dns:read
POST /v1/labels Create a label for this account. writes domains:write
GET /v1/labels Every label in this account. domains:read
PATCH /v1/labels/:id Rename or recolour a label. An omitted field is left alone; an explicit null clears it. writes domains:write
DELETE /v1/labels/:id Delete a label and every attachment of it. The things it was attached to are untouched. writes domains:write
POST /v1/labels/:id/attachments Attach a label to a domain, an address or a template, or detach it. Idempotent. writes domains:write
GET /v1/domains/:id/labels The labels on one domain. domains:read
GET /v1/registrant-contacts/:id/labels The labels on one registrant address. domains:read
GET /v1/dns-templates/:id/labels The labels on one DNS record template. dns:read
GET /v1/registrant-contacts Every registrant address in this account. Retired ones only when asked for. domains:read
GET /v1/registrant-contacts/:id One registrant address. domains:read
PATCH /v1/registrant-contacts/:id Edit an address. Refused once a domain has been registered under it. writes domains:write
POST /v1/registrant-contacts/:id/default Make this the address new registrations use. Exactly one account default. writes domains:write
POST /v1/registrant-contacts/:id/archive Retire an address. Never deleted: a registered domain still points at it. writes domains:write
POST /v1/dns-templates Store a reusable set of records. Checked whole: every placeholder must be declared. writes dns:write
GET /v1/dns-templates Every template in this account, with its records and variables. dns:read
GET /v1/dns-templates/:id One template, whole. dns:read
POST /v1/dns-templates/:id/archive Archive a template. Never deleted: a record of having applied it must still resolve. writes dns:write
POST /v1/domains/:id/dns/templates/:templateId/plan What applying this template to this domain would change. Writes nothing. dns:read
GET /v1/billing/terms The Terms version a top-up requires, and whether this account has accepted it. billing:read
POST /v1/billing/terms Record that the person accepted the Terms. Required once before a top-up. writes Person only · API/CLI billing:write
GET /v1/billing The account balance and its ledger. Every charge and credit, with its cause. billing:read
POST /v1/billing/topup Start a top-up. Returns a Checkout URL for a human to open; no card touches this API. writes billing:write

MCP

Point your agent at whydot-mcp for the agent operations above, with the same scopes. Terms acceptance is a human step through the API or CLI; it is not an MCP tool. An agent can read Terms status to know when your action is needed.

Manual MCP setup
claude mcp add whydot -- whydot-mcp in Claude Code. In any other harness, a stdio server whose command is whydot-mcp.