Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .agents/skills/gddy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# gddy skill

Teaches an AI coding agent how to drive `gddy`, GoDaddy's beta CLI for domain search, registration, and DNS management. It covers install/auth, the two-step quote-then-purchase flow for buying a domain, DNS record semantics (`add` vs `set` vs `delete`), and — since `gddy` moves faster than its own docs — how to fetch GoDaddy's developer docs correctly and when to trust `gddy --help` over a doc page.

See [SKILL.md](./SKILL.md) for the full instructions given to the agent.

## Installation

### Claude Code

```bash
claude plugin marketplace add godaddy/cli
claude plugin install godaddy-cli@godaddy
```

This installs the plugin that bundles both skills in this repo (`godaddy-cli` and `gddy`); Claude picks whichever one fits the task automatically.

### Any other AI coding agent

This repo is also compatible with [skills](https://github.com/vercel-labs/skills), a package-manager-style installer for agent skills that isn't tied to Claude Code — it supports Cursor, Codex, Windsurf, opencode, and 70+ other agents in addition to Claude Code:

```bash
npx skills add godaddy/cli --skill gddy --agent claude-code
```

Swap `--agent claude-code` for whichever agent you use (`cursor`, `codex`, `windsurf`, `opencode`, ...). Run `npx skills add --help` for the full list of supported agents.
Comment thread
jpage-godaddy marked this conversation as resolved.
Outdated

## What it doesn't cover

Applications, auth, environments, releases/deploys, extensions, and webhooks live in a separate, older tool, `godaddy`, with its own skill — see [../godaddy-cli/README.md](../godaddy-cli/README.md).
112 changes: 112 additions & 0 deletions .agents/skills/gddy/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
name: gddy
description: Use GoDaddy's beta CLI (`gddy`) to search, register, and manage domains and DNS records. Load this skill whenever a task involves running `gddy` commands, parsing their JSON output, finding or buying a domain, editing DNS records (A, CNAME, MX, TXT, etc.) for a domain hosted at GoDaddy, or reading a page under developer.godaddy.com/docs/api-users/**. Also trigger any time Claude is about to fetch a GoDaddy developer-docs page, even mid-task, since it changes how that fetch should be done. `gddy` is a separate tool from GoDaddy's older `godaddy` CLI (applications, deployments, webhooks) — do not use this skill for that tool, and don't trigger for other registrars or DNS providers (Cloudflare, Route 53, Namecheap, etc.) unless GoDaddy is explicitly involved.
---
Comment thread
dkoopman-godaddy marked this conversation as resolved.

# gddy — GoDaddy domains & DNS CLI

`gddy` is GoDaddy's beta CLI for domain search, registration, and DNS management. It's a separate, independently-installed tool from GoDaddy's older `godaddy` CLI (applications, deployments, webhooks) — different binary, different install method, different auth and config. Installing or using one doesn't affect the other. For application, deployment, or webhook tasks, use the `godaddy-cli` skill instead of this one.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

Both tools exist side by side because `gddy` is the newer of the two and under active development, with more surface area on its roadmap than what's documented here — it already has early, not-yet-stable support for things like applications and webhooks alongside its domain/DNS focus. Stick to the domain/DNS commands documented in this skill unless you've confirmed a newer capability is ready via `gddy --help`.

It's under active development, and moves faster than its own docs and README — see "When the CLI and the docs disagree" below.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

## Fetching GoDaddy developer docs: curl the llms.mdx mirror, don't WebFetch the HTML
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

Read this before fetching anything under `developer.godaddy.com/docs/**`.

WebFetch always pipes the page through a summarizing model, no matter what the prompt says. For documentation with exact command syntax, flag names, and code samples, that summarization silently drops or rewrites details — a flag gets dropped, a code sample gets paraphrased into something that no longer runs. GoDaddy publishes a full-text markdown mirror of every docs page specifically so agents can get the real content instead. Use it.

To read any docs page, curl its markdown mirror instead of fetching the HTML:

```bash
# HTML page: https://developer.godaddy.com/docs/api-users/cli-setup
# curl this: https://developer.godaddy.com/llms.mdx/api-users/cli-setup
curl -fsSL https://developer.godaddy.com/llms.mdx/api-users/cli-setup
```

The rule for deriving the URL: take the path after `/docs/` (or `/en/docs/`), and fetch `https://developer.godaddy.com/llms.mdx/<that-path>`. This applies even if the user hands you the HTML URL directly — rewrite it yourself before fetching. If you only need the table of contents for a section, `https://developer.godaddy.com/llms.mdx/api-users` (no subpage) gives the full page tree for that section.

Do this for every GoDaddy docs page you touch, not just ones the user explicitly names — if a task leads you to open another page on the same docs site partway through, curl its mirror too rather than falling back to WebFetch.

## When the CLI and the docs disagree, trust the CLI

`gddy`'s own `--help` output reflects the actual installed version; docs and the README can lag behind a release, since it's beta and moves fast. Before relying on a remembered or documented flag shape, especially for anything destructive or paid, run `gddy <command> --help` and trust that over any doc page or README. This matters most for domain purchase, which is a two-step flow that some docs oversimplify (see below).

## Setup

Install:

```bash
# macOS / Linux / Git Bash / MSYS2 / Cygwin
curl -fsSL https://github.com/godaddy/cli/releases/latest/download/install.sh | bash

# PowerShell
irm https://github.com/godaddy/cli/releases/latest/download/install.ps1 | iex
```

Verify with `gddy --version`. This installs the `gddy` binary alongside any existing `godaddy` CLI — the two are separate tools.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

Authenticate with `gddy auth login` (opens a browser for OAuth). Check state with `gddy auth status`, sign out with `gddy auth logout`. For non-interactive use (CI, scripts), use a Personal Access Token instead — manage one with `gddy pat add/list/remove`, or set the `GDDY_PAT`/`GDDY_PAT_<ENV>` env var directly (checked before OAuth). Note PATs can't do everything: domain purchase specifically requires a customer-scoped OAuth login (see below).

Every command accepts `--env <ote|prod>` to pick environment (default `prod`) and `--debug` for verbose output.

## Domain purchase: it's a two-step quote-then-purchase flow, not one command
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

This is the highest-stakes command in the CLI — it charges money and can't be undone — so get the shape right. Some docs and even the README show it as a single `gddy domain purchase <domain> --agree --confirm` call; that's a simplification and doesn't match what the CLI actually does. The real flow locks in registration terms first, then executes against that locked quote:

1. **Quote** — decide the registration period, privacy, and nameservers here; they get baked into the quote token:
```bash
gddy domain quote example.com --period 1 --privacy
```
Returns a single-use `quoteToken` valid for roughly 10 minutes, cached locally alongside the contacts file.

2. **Purchase** — spend the quote token:
```bash
gddy domain purchase --quote-token <token> --agree --confirm
```
`--agree` means "I consent to this quote's required legal agreements" — leave it off once first if you want to see what agreements apply before agreeing. `--confirm` is a separate, explicit acknowledgment that this charges the account. Both are required; there's no lower-friction path, by design. Purchase needs an OAuth login (`gddy auth login`) — a bare PAT is rejected here even though PATs work fine for read commands.

3. Purchase is async. The command waits briefly and reports status; if it's still pending, check back with `gddy domain operation status <operation-id>`. A completed purchase shows up in `gddy domain list`.

Before quoting, contact info needs to exist: `gddy domain contacts init` writes a starter `contacts.toml` template (registrant/admin/billing/tech, all commented out) to the OS config directory. Any role left commented out falls back to the account default; any role you fill in needs all of its required fields (name, email, phone, full address).

Always confirm with the user before running `purchase` — it's real money, and the action is not reversible.

## Domain search and lookup

```bash
gddy domain suggest "coffee shop" --tlds com --tlds net --length-min 4 --length-max 15
gddy domain available example.com --check-type fast # or: full (live registry check, slower)
gddy domain list --status ACTIVE
gddy domain get example.com
gddy domain agreements --tld com --privacy
```

Global `--limit <N>` caps result counts on list-like commands.

## DNS management
Comment thread
dkoopman-godaddy marked this conversation as resolved.

Valid record types: `A AAAA ALIAS CAA CNAME MX NS SOA SRV TXT`. `NS` and `SOA` are GoDaddy-managed and read-only — you can list them but not add/set/delete them.

```bash
gddy dns list example.com --type A
gddy dns add example.com --type A --name www --data 192.0.2.1 --ttl 3600
gddy dns set example.com --type TXT --name @ --data "v=spf1 -all"
gddy dns delete example.com --type A --name www
```

`add` appends a new record; `set` replaces every record matching that type+name; `delete` removes every record matching that type+name. Type-specific requirements: `MX`/`SRV` need `--priority`; `SRV` also needs `--port`, `--weight`, `--protocol`, `--service`; `CAA` requires `--tag` (`--flag` is optional).

`set` and `delete` are destructive — support `--dry-run` to preview the change and `--reason <text>` for an audit trail. Run with `--dry-run` first and show the user what would change before applying it for real.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

## Payments

`gddy payments add` opens the browser to the account's payment-methods page — no card data is ever handled by the CLI itself. Purchases fail (403/422) without a valid payment method or Good-as-Gold balance on the account; check the error's `code` field, not just the HTTP status, to tell that apart from other failures.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

## Reference material

Read these only when the task needs the detail — they're not needed for common domain/DNS operations:

- `reference/api.md` — raw GoDaddy Domains API endpoints (when `gddy` isn't installed/available, e.g. CI in a non-shell language): availability/suggestions, the registration-quote → registration flow with idempotency keys, pagination, and the MCP server.
- `reference/errors-and-limits.md` — error envelope shape, retry/idempotency rules per HTTP method, and rate-limit headers/handling.
84 changes: 84 additions & 0 deletions .agents/skills/gddy/reference/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# GoDaddy Domains API (raw HTTP fallback)

Use this when the `gddy` CLI isn't installed or isn't a good fit for the task (CI pipelines, non-shell languages, etc.). When `gddy` is available, prefer it — it handles auth, quote-token bookkeeping, and idempotency for you.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

Base URL: `https://api.godaddy.com`
Comment thread
dkoopman-godaddy marked this conversation as resolved.

Auth header: `Authorization: Bearer $GODADDY_PAT` (PAT generated from the Personal Access Token page under `https://developer.godaddy.com/docs/api-users/auth`). Legacy `sso-key key:secret` credentials still work for v1/v2 endpoints but not v3, and are deprecated — prefer a PAT for anything new.
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

## Search and availability
Comment thread
dkoopman-godaddy marked this conversation as resolved.
Outdated

```bash
curl -s "https://api.godaddy.com/v3/domains/check-availability?domain=example.com&optimizeFor=SPEED" \
-H "Authorization: Bearer $GODADDY_PAT"
```

`optimizeFor` is `SPEED` (cached, fast) or `ACCURACY` (live registry check, slower). Prices are in cents — divide by 100.

```bash
curl -s "https://api.godaddy.com/v3/domains/suggestions?query=coffee+shop&tlds=com,net&pageSize=25&lengthMin=4&lengthMax=15" \
-H "Authorization: Bearer $GODADDY_PAT"
```

`sources` can further filter suggestion sources: `EXTENSION, KEYWORD_SPIN, CC_TLD, PREMIUM`.

For checking many domains at once instead of one-by-one, `POST /v1/domains/available` accepts an array of names in one request — much cheaper against the rate limit than looping single checks.

## Registration: quote, then execute

Mirrors the CLI's `gddy domain quote` / `gddy domain purchase` split — registration is always two calls, never one.

1. Lock a quote:
```bash
curl -s -X POST "https://api.godaddy.com/v3/domains/registration-quotes" \
-H "Authorization: Bearer $GODADDY_PAT" -H "Content-Type: application/json" \
-d '{"domain": "example.com", "period": 1}'
```
Returns `{quoteToken, expiresAt, requiredAgreements}`. The token is single-use and short-lived.

2. Execute the registration against that token:
```bash
curl -s -X POST "https://api.godaddy.com/v3/domains/registrations" \
-H "Authorization: Bearer $GODADDY_PAT" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"quoteToken": "<token>", "domain": "example.com", "period": 1, "consent": {"agreementTypes": [...], "agreedAt": "<iso8601>"}}'
```
The `Idempotency-Key` header is required, not optional — registration is not safely retryable without one. Retrying the same request with a *new* key can register (and charge for) the domain twice; always reuse the same key when retrying the same logical attempt.

3. Poll for completion:
```bash
curl -s "https://api.godaddy.com/v3/domains/registrations/<registrationId>" -H "Authorization: Bearer $GODADDY_PAT"
# or
curl -s "https://api.godaddy.com/v3/domains/operations/<operationId>" -H "Authorization: Bearer $GODADDY_PAT"
```

## Listing domains (pagination)

`GET /v1/domains` uses cursor pagination via `limit` and `marker` — repeat with `marker` set to the last domain name from the previous page until a page comes back shorter than `limit`:

```bash
curl -s "https://api.godaddy.com/v1/domains?limit=100" -H "Authorization: Bearer $GODADDY_PAT"
curl -s "https://api.godaddy.com/v1/domains?limit=100&marker=last-domain-from-previous-page.com" \
-H "Authorization: Bearer $GODADDY_PAT"
```

v2 list endpoints (domain forwarding, actions, etc.) return the entire collection in one response and don't take `limit`/`marker` at all. A page walk is safe to interrupt and resume — retry the same `(limit, marker)` pair on failure.

## MCP server (read-only, public data only)

`https://api.godaddy.com/v1/domains/mcp` (streamable-http transport) exposes public domain search and availability tools with no authentication required:

```json
{
"mcpServers": {
"godaddy": {
"url": "https://api.godaddy.com/v1/domains/mcp",
"transport": "streamable-http"
}
}
}
```

It cannot register domains, touch DNS, or do anything account-specific — it's a convenience for pure discovery ("is this domain available?", "suggest names for X"). For anything authenticated (purchase, DNS, account domains), use the CLI or the endpoints above instead.

Full docs: `https://developer.godaddy.com/docs/api-users/mcp` — curl the `llms.mdx` mirror per the guidance in SKILL.md rather than fetching that page directly.
73 changes: 73 additions & 0 deletions .agents/skills/gddy/reference/errors-and-limits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Errors, retries, and rate limits

## Error shape

Every error response is a stable JSON envelope:

```json
{
"code": "INVALID_DOMAIN",
"message": "example is not a valid domain name",
"fields": [
{ "path": "domain", "code": "INVALID_FORMAT", "message": "..." }
]
}
```

Always branch on `code`, never on `message` — message text can change between releases and isn't a stable contract. `fields` is present on validation errors (422) and points at which field(s) failed and why.

429 (rate limited) responses add a `retryAfterSec` field and otherwise carry little useful body — read the headers instead (below).

## Retry semantics — depends on the HTTP method, not just "is it safe to retry"

| Operation | Idempotent? | Notes |
|---|---|---|
| Any `GET` | Yes | Always safe to retry. |
| `POST /v1/domains/purchase` (and registration create) | **No** | Retrying without reusing an `Idempotency-Key` (v3) or otherwise confirming state first can double-purchase/double-charge. Check current state (e.g. does the domain already show up under the account) before retrying a failed purchase. |
| `PUT` (e.g. DNS record replace / `gddy dns set`) | Yes | Safe to retry — it fully replaces state each time. |
| `PATCH` (e.g. DNS record add / `gddy dns add`) | **No** | Appends; retrying a failed "add" can create duplicate records. Check current state before retrying. |
| `DELETE` (e.g. `gddy dns delete`) | Yes | Safe to retry — deleting something already gone is a no-op. |

## Rate limits

60 requests/minute per credential, applied regardless of endpoint. Every response — not just 429s — carries these headers, so you can self-throttle before hitting the limit rather than reacting after:

| Header | Meaning |
|---|---|
| `RateLimit-Limit` | Limit that applies to this request |
| `RateLimit-Remaining` | Requests left in the current window |
| `RateLimit-Reset` | Seconds until the window resets |

On a 429, back off for at least `RateLimit-Reset` seconds (or the `retryAfterSec` field), plus some jitter if retrying programmatically in a loop.

To stay under the limit in the first place:
- Prefer bulk endpoints where they exist (e.g. `POST /v1/domains/available` for many domains at once, instead of looping single `check-availability` calls).
- Use cursor pagination (`limit`/`marker`) sequentially rather than fanning out parallel page requests.
- Don't share one credential across many independent callers and assume the limit is per-account — it's per-credential today, but that's an implementation detail, not a guarantee.

If a legitimate use case needs a sustained rate above 60/min, that's a conversation with GoDaddy developer support, not something to work around client-side.

## Common error codes (registration)

These are the `code` values you'll actually see while quoting/registering a domain, with what each means:

| `code` | Meaning | What to do |
|---|---|---|
| `DOMAIN_NOT_AVAILABLE` | Someone else registered the name first (race between check and purchase). | Re-check availability, suggest alternatives. |
| `BILLING_DECLINED` | Payment method on file was charged and declined. | Surface to the user — they need to fix their payment method. |
| `NO_PAYMENT_PROFILE` | No payment method on the account at all. | Direct the user to `gddy payments add` or the account's payment-methods page. |
| `QUOTE_MISMATCH` | The `period` (or other term) at execute time doesn't match what was quoted. | Reuse the exact period from the quote, or fetch a fresh quote. |
| `INVALID_AGREEMENT_KEYS` | `agreementTypes` sent don't match the TLD's `requiredAgreements` from the quote. | Use the exact keys the quote response returned, not guessed/remembered ones. |
| `MISSING_CONTACT` | No registrant contact configured on the account. | Set up contacts (`gddy domain contacts init`, then fill in the file) before quoting. |
| `MISSING_BILLING_PHONE` | Contact phone is missing or malformed. | Verify the contact has a complete, valid phone number. |

## Common status codes and what to do

- **400** — malformed request (bad JSON, missing required field shape). Fix the request; don't retry as-is.
- **401** — missing/invalid/expired credential. Re-authenticate (`gddy auth login` or refresh the PAT) rather than retry.
- **403** — authenticated but not authorized for this action (e.g. a PAT trying to purchase, which requires OAuth; or no payment method on file). Check `code` to distinguish "wrong credential type" from "account not payment-ready."
- **404** — resource doesn't exist (domain not in the account, unknown operation ID). Don't retry.
- **409** — conflict with current state (e.g. domain already has a pending operation). Check current state before retrying.
- **422** — validation failure; see `fields` for which field(s) and why.
- **429** — rate limited; see above.
- **5xx** — server-side; safe to retry idempotent operations with backoff, not safe to retry non-idempotent ones (see table above) without first checking state.
Loading