name.com now publishes an official Go SDK for the Core API:
https://github.com/namedotcom/core-api-go (MIT, Fern-generated, v1.33.2).
It did not exist when this CLI was built, which is why internal/api/gen exists
at all. It is worth evaluating whether adopting it lets us delete most of that.
What it could replace
| Today |
With the SDK |
internal/api/gen/zz_generated.go — 23,381 generated lines |
github.com/namedotcom/core-api-go |
namecom.api.yaml vendored spec + make verify-spec SHA pin |
upstream's problem |
scripts/spec_to_30.py — the OpenAPI 3.1 → 3.0 preprocessor |
gone |
make generate + oapi-codegen |
gone |
retry/backoff in internal/api/transport.go |
built in (exponential, configurable limit, default 2) |
parseError() in internal/api/apierror.go |
core.APIError, errors.As-compatible |
The preprocessor is the part worth highlighting. It exists solely because
oapi-codegen v2.4.x lacks OpenAPI 3.1 support, and it carries three documented
workarounds: nullable type: [T, null] unions, bare - type: null oneOf
members, and 33 *Response schema names renamed to *ResponseSchema to avoid
colliding with generated operation wrappers. All of that is scaffolding for a
problem the SDK does not have.
It should also retire the "Key generated type gotchas" section of CLAUDE.md —
Record.Ttl being int64 while body Ttl is *int64, Record.Type being
*string while create/update need a gen.DNSCreateRecordBodyType(str) cast,
DomainResponsePayload.Locked being a bool alias rather than *bool. Those
are artifacts of our codegen path, and every one of them is a place a
contributor has to be told something non-obvious.
Endpoint coverage looks complete
The SDK's service packages line up with our command groups, with room to spare:
domains dns dnssecs emailforwardings urlforwardings vanitynameservers
transfers orders refunds contactverification tldpricing premiumdomains
accountinfo domaininfo accounts webhooknotifications
webhooknotifications, premiumdomains, and accounts are endpoints we do not
currently surface. Coverage still needs verifying call-by-call against what
cmd/ actually invokes — this list is a directory listing, not a guarantee.
What does not come for free
These are the reasons this is an evaluation issue and not a straightforward
swap. Each needs an answer before committing.
-
Client-side rate limiting. We run a x/time/rate limiter at 10 req/s
with burst 5 in internal/api/transport.go. The SDK documents retries but
not rate limiting. Probably preserved by passing our own instrumented
*http.Client via option.WithHTTPClient — needs confirming.
-
Idempotency-key gating on POST retries. Our transport retries a POST
only when X-Idempotency-Key is set, which is what keeps a retried
registration from becoming two registrations. The SDK's legacy retry
profile retries 408/429/5XX; we need to know whether it applies that to
unsafe methods, and whether --idempotency-key can be threaded through. This
is the highest-stakes item on the list — getting it wrong costs real money.
-
Auth shape. We set an Authorization header directly (client.go:134)
and deliberately let namecom api --header 'Authorization: …' override it.
The SDK exposes option.WithBasicAuth(username, password) and
option.WithToken. Need to confirm which one name.com Core expects and that
the escape hatch survives.
-
Flags that reach into the transport. --base-url maps cleanly onto
option.WithBaseURL, and --sandbox onto the SDK's environments. --debug
/ --debug-file and the User-Agent both live in our http.Client, so they
ride along with item 1.
-
namecom api raw passthrough. cmd/apicmd uses Client.HTTPClient()
directly and does not care about generated types. It needs whatever
configured *http.Client we end up with, not the typed surface.
Risk
The SDK is new — repo created 2026-07-02, last pushed 2026-08-18. One star,
and Fern regenerates it, so expect version churn and the possibility of
breaking changes between minor tags. Dependencies are light (google/uuid,
testify) and go.mod declares go 1.22, so nothing conflicts with our
1.26.6 toolchain. MIT on both sides.
Worth weighing against the status quo, which is not free either: we currently
own a spec pin, a Python preprocessor, and a codegen step that no upstream
maintains for us.
Suggested first step
Spike one command group — dns is a good candidate, since it exercises reads,
the read-modify-write update path, and typed enums — against the SDK on a
branch, without deleting anything. That answers items 1–3 concretely and gives
a real diff to judge the ergonomics from, before committing to a migration that
touches every command.
name.com now publishes an official Go SDK for the Core API:
https://github.com/namedotcom/core-api-go (MIT, Fern-generated,
v1.33.2).It did not exist when this CLI was built, which is why
internal/api/genexistsat all. It is worth evaluating whether adopting it lets us delete most of that.
What it could replace
internal/api/gen/zz_generated.go— 23,381 generated linesgithub.com/namedotcom/core-api-gonamecom.api.yamlvendored spec +make verify-specSHA pinscripts/spec_to_30.py— the OpenAPI 3.1 → 3.0 preprocessormake generate+ oapi-codegeninternal/api/transport.goparseError()ininternal/api/apierror.gocore.APIError,errors.As-compatibleThe preprocessor is the part worth highlighting. It exists solely because
oapi-codegen v2.4.x lacks OpenAPI 3.1 support, and it carries three documented
workarounds: nullable
type: [T, null]unions, bare- type: nulloneOfmembers, and 33
*Responseschema names renamed to*ResponseSchemato avoidcolliding with generated operation wrappers. All of that is scaffolding for a
problem the SDK does not have.
It should also retire the "Key generated type gotchas" section of
CLAUDE.md—Record.Ttlbeingint64while bodyTtlis*int64,Record.Typebeing*stringwhile create/update need agen.DNSCreateRecordBodyType(str)cast,DomainResponsePayload.Lockedbeing aboolalias rather than*bool. Thoseare artifacts of our codegen path, and every one of them is a place a
contributor has to be told something non-obvious.
Endpoint coverage looks complete
The SDK's service packages line up with our command groups, with room to spare:
webhooknotifications,premiumdomains, andaccountsare endpoints we do notcurrently surface. Coverage still needs verifying call-by-call against what
cmd/actually invokes — this list is a directory listing, not a guarantee.What does not come for free
These are the reasons this is an evaluation issue and not a straightforward
swap. Each needs an answer before committing.
Client-side rate limiting. We run a
x/time/ratelimiter at 10 req/swith burst 5 in
internal/api/transport.go. The SDK documents retries butnot rate limiting. Probably preserved by passing our own instrumented
*http.Clientviaoption.WithHTTPClient— needs confirming.Idempotency-key gating on POST retries. Our transport retries a POST
only when
X-Idempotency-Keyis set, which is what keeps a retriedregistration from becoming two registrations. The SDK's
legacyretryprofile retries 408/429/5XX; we need to know whether it applies that to
unsafe methods, and whether
--idempotency-keycan be threaded through. Thisis the highest-stakes item on the list — getting it wrong costs real money.
Auth shape. We set an
Authorizationheader directly (client.go:134)and deliberately let
namecom api --header 'Authorization: …'override it.The SDK exposes
option.WithBasicAuth(username, password)andoption.WithToken. Need to confirm which one name.com Core expects and thatthe escape hatch survives.
Flags that reach into the transport.
--base-urlmaps cleanly ontooption.WithBaseURL, and--sandboxonto the SDK's environments.--debug/
--debug-fileand the User-Agent both live in ourhttp.Client, so theyride along with item 1.
namecom apiraw passthrough.cmd/apicmdusesClient.HTTPClient()directly and does not care about generated types. It needs whatever
configured
*http.Clientwe end up with, not the typed surface.Risk
The SDK is new — repo created 2026-07-02, last pushed 2026-08-18. One star,
and Fern regenerates it, so expect version churn and the possibility of
breaking changes between minor tags. Dependencies are light (
google/uuid,testify) andgo.moddeclaresgo 1.22, so nothing conflicts with our1.26.6 toolchain. MIT on both sides.
Worth weighing against the status quo, which is not free either: we currently
own a spec pin, a Python preprocessor, and a codegen step that no upstream
maintains for us.
Suggested first step
Spike one command group —
dnsis a good candidate, since it exercises reads,the read-modify-write update path, and typed enums — against the SDK on a
branch, without deleting anything. That answers items 1–3 concretely and gives
a real diff to judge the ergonomics from, before committing to a migration that
touches every command.