Hanzo

Domain

Package domain is Hanzo Domains: search a name, see the price, buy it from your prepaid wallet.

Package domain is Hanzo Domains: search a name, see the price, buy it from your prepaid wallet.

Base URLhttps://api.hanzo.ai
Operations7
AuthAuthorization: Bearer $HANZO_API_KEY

Specification

HIP-1123 · Domain — Name Registration — Draft · read the specification →

/v1/domain is Hanzo Domains: search a name, see the price, buy it from the org's prepaid balance. It is implemented in hanzoai/cloud at apps/domain, reselling a wholesale registrar behind one interface and handing every new zone to Hanzo DNS. This HIP states the purchase pipeline, where the money moves, and what the ownership store is and is not.

Motivation

DNS manages records for a domain an org already controls; nothing acquired the domain. Domains is the acquisition product, distinct on purpose (apps/domain/domain.go:8-12): buy here, manage records there. The core is transport-free — availability → price → authorize → register → provision-zone → capture → record, orchestrated over four interfaces (Registrar, Biller, Zones, Store) — so the policy is unit-testable with no HTTP, registrar or billing backend (apps/domain/domain.go:13-18).

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 The store, honestly

The registrar account is the authority on what is registered. What domain owns is the domain↔org Holding row it writes on a successful purchase, and its default Store is in-memory (apps/domain/store.go:9-13, MemStore) — sufficient for a single-process deployment, swapped behind the same interface for a durable one in a multi-replica deployment. A restart loses the projection, never the registration.

§2 The addresses

Every route is under /v1/domain (manifest/apps.go:162) and every operation is typed: health, search, availability, the org's holdings, register, renew, transfer (apps/domain/mount.go:24-32).

§3 The price and the debit

The price a customer sees carries the markup applied in exactly one place (apps/domain/pricing.go:11-16): multiplier over wholesale, a minimum absolute margin, rounded up to whole cents, never below cost. A purchase is two-phase through the Biller (apps/domain/domain.go:57-71): Authorize refuses with 402 when the prepaid balance cannot cover the marked-up cents — before the registrar is touched — and Capture debits after the registrar succeeds. The Biller is cloud's ResourceMeter (apps/domain/mount.go:56, mount.go:159-186): Gate is the authorization, MeterUsage under the domain.register meter is the capture, so the debit lands on the org's ledger through the same money plane as every other charge. The plugin declares cloud.Metered (plugin/domain/main.go:29) and the capability is in spend.go's metered list (spend.go:299): every purchase moves money, in integer cents.

§4 Tenancy

Every read and every mutation resolves the org from the validated principal (principal.Acting, apps/domain/mount.go:417, HIP-0026); the org owns the purchase and is the ledger the charge lands on. Renew and transfer on a domain the org does not hold answer ErrNotOwned; a purchase of a name the org already holds answers ErrAlreadyOwned (apps/domain/domain.go:29-40).

§5 Money, events, telemetry

The metered facts are in §3. domain publishes no events on the bus, and emits nothing to observability beyond the request span every route gets.

§6 Stage

domain is ga: acquiring a name for a deployment is developer tooling in the agentic-OS core, not a vertical application.

§7 Upstream

domain derives from no forked code. It implements the name.com Core API v4 wire as its wholesale registrar client (apps/domain/namecom), and hands zones to hanzoai/dns. Registrar credentials arrive as operator-injected env from the platform secret store, never hard-coded (apps/domain/mount.go:34-37).

Rationale

Two-phase billing with authorize-before-registrar, rather than charge-then-buy or buy-then-charge, is the only order in which neither party is left holding the other's failure: a refused balance costs the registrar nothing, and a registrar failure costs the customer nothing. Capture deliberately takes no idempotency key named after the domain (apps/domain/domain.go:63-70): a renew and a lapse-and-rebuy are distinct acts, and keying the ledger by the name silently collapsed them into one charge.

Security Considerations

The wrong implementation spends someone else's balance or sells below cost. The org on a purchase comes only from the validated principal, so a caller cannot name the ledger to debit. The markup floor is clamped at 1 and the sell price at cost (apps/domain/pricing.go:23-34), so no configuration sells below wholesale. A deployment with no registrar credential fails every purchase closed with 503 (ErrNotConfigured), and the credential itself lives in the secret store, reachable only as injected env.

Four surfaces

SurfaceReaches this capability asCoverage
RESTdomain at its own prefix7 operations
CLIhanzo domain …7 of 7
SDKDomainApi in every published client7 methods
MCPtool domain on https://api.hanzo.ai/v1/mcp7 operations, 3 under the document's own id — ask describe for the rest

Quickstart

export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys

Then the first call — a read that needs nothing but the key. GET /v1/domain/health, operation get_domain_health:

hanzo domain health

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
GET /v1/domain/availabilityChecks exact names rather than searching for them, and answers the same quote shape search does — purchasable, premium, first-term and renewal price…
GET /v1/domain/domainsIs the domains your org has bought here, newest registration first, each carrying the name, when it was registered, when it expires, what the org…
GET /v1/domain/healthReports registrar reachability honestly: ok only when the wholesale credentials are present AND name.com accepted them on a live call made while you…
POST /v1/domain/registerBuys a domain for your org and answers the ownership record together with the quote it was bought at.
POST /v1/domain/renewExtends a domain your org already owns and answers the updated record with its new expiry alongside what was paid.
GET /v1/domain/searchFinds names built from the keyword q, plus the registrar's alternate-TLD suggestions, and answers a quote for each: the name, whether it is…
POST /v1/domain/transferMoves a domain you own at another registrar onto your org here, using its authCode, and answers the same record-plus-quote a purchase does.

All Hanzo APIs · Interactive reference

How is this guide?

On this page