# DomainGenius
---
# Welcome
DomainGenius is a domain registrar built for people who like the command line as much as the dashboard.
URL: /introduction
DomainGenius is an Australian-licensed domain registrar. There's a dashboard if you want to point and click, a JSON HTTP API for everything else, and an MCP server if you want an AI assistant to handle it. All three wrap the same backend, so what you can do in one, you can do in the others.
## What you get
- **Registration** across `.com`, `.com.au`, `.net`, `.org`, and the rest of the .au family.
- **DNS** on Cloudflare's edge. A/AAAA/CNAME/MX/TXT plus presets for Vercel, Google Workspace, Microsoft 365, and the rest of the usual suspects.
- **Transfers** in and out. EPP auth codes you actually own.
- **Marketplace** for buying parked names and listing your own.
- **Valuation, search, and traffic tools** — the same data we use to price our own portfolio.
- **Prepaid balance** with auto-top-up. No surprise card declines mid-renewal.
## Pick your path
The fastest way to get a domain registered. Sign up, search, buy.
REST/JSON. API keys with scoped permissions. OpenAPI spec.
Connect the MCP server to Claude, Cursor, Windsurf, etc.
## Where to next
- New here? Run through the [Quickstart](/quickstart) — sign up, mint a key, register your first domain in five minutes.
- Need a mental model? [Concepts](/concepts) defines the words we use everywhere else in these docs.
- Looking for an answer to a specific question? Try the [FAQ](/faq/registration).
DomainGenius is a trading name of Nine Primes Pty Ltd, an [auDA](https://www.auda.org.au)-accredited registrar.
---
# Quickstart
Sign up, mint an API key, and register a domain — five minutes.
URL: /quickstart
By the end you'll have a working API key and a domain registered against your org's balance. Five minutes if you're not stopping for tea.
## Prerequisites
- A DomainGenius account ([sign up](https://domaingenius.com.au/signup) — free).
- A [`bun`](https://bun.sh) or `curl` you can run.
- For `.au` domains: an ABN. Other TLDs have no eligibility check.
## 1. Top up the org balance
In the dashboard, [Billing → Top up](https://app.domaingenius.com.au/dashboard/billing). $50 is plenty for a `.com.au`.
## 2. Mint an API key
[API keys → New key](https://app.domaingenius.com.au/dashboard/api-keys). Give it `availability:read` and `domains:write`. Copy the value (it's only shown once).
```bash
export DG_KEY=dg_live_...
```
## 3. Find your org OID
```bash
curl -s https://api.domaingenius.com.au/api/v1/me/orgs \
-H "Authorization: Bearer $DG_KEY" | bun -e \
'const r = await Bun.stdin.json(); console.log(r.items[0].oid);'
```
```text Output
org_01HF82YV...
```
```bash
export DG_ORG=org_01HF82YV...
```
## 4. Check availability
```bash
curl "https://api.domaingenius.com.au/api/v1/domains/availability?domain=hello-world.com.au" \
-H "Authorization: Bearer $DG_KEY"
```
```json
{
"domain": "hello-world.com.au",
"available": true,
"register_price_aud": 24.95
}
```
## 5. Register it
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/hello-world.com.au/register" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "years": 1 }'
```
```json
{
"status": "registered",
"domain": "hello-world.com.au",
"expires_at": "2027-05-01T00:00:00Z"
}
```
The domain shows up in the dashboard immediately. DNS, contacts, and forwarding can be configured next — see the relevant guides.
## What now
Add A, MX, TXT records or apply a preset.
Registrant, admin, technical, billing.
Drive the same flows from Claude or Cursor.
Every endpoint, with a try-it.
---
# Concepts
The vocabulary the rest of the docs assumes you know.
URL: /concepts
## Account, organisation, member
You sign in as a **user**. Every action runs inside an **organisation** (org). That's where domains, billing, and contacts live. A solo account is a one-member org under the hood.
A user can belong to multiple orgs. Each membership has a **role** — `owner`, `admin`, or `member`. Some operations require admin or owner.
Org identifiers are opaque strings prefixed `org_`. You'll see the OID in URLs and tool calls. Don't parse it.
## Domain states
| State | Meaning |
| --- | --- |
| `pending` | We've requested registration; the registry hasn't confirmed yet. |
| `registered` | Live — the domain resolves and we own it on your behalf. |
| `expired` | Past expiry, in the registry's renewal grace window. Still recoverable. |
| `redemption` | Past grace, in redemption. Costs more to recover; clock is ticking. |
| `external` | The domain belongs to your org but is at another registrar (used for transfer-out tracking). |
| `deleted` | Released to the registry pool. |
| `failed` | Registration attempt failed; see `last_error`. |
`auto_renew` and `expiry` belong to all live states.
## Contacts and roles
A **contact** is a reusable address record (name, address, phone, email). On a registered domain you can assign up to four roles:
- `registrant` — the legal owner.
- `admin` — receives administrative notifications.
- `technical` — receives technical/abuse notifications.
- `billing` — receives renewal notices.
The same contact record can fill multiple roles, and one contact can be assigned to many domains. Changing a contact updates every domain that references it on the next sync.
## DNS management
A domain's `dns_management` is either `domaingenius` (we host the zone on Cloudflare and you edit records via the API/MCP/dashboard) or `external` (you point the nameservers somewhere else). Toggle with `update_domain_settings` or via the dashboard.
A **preset** is a bundle of DNS records that configure a common service (Vercel, Google Workspace MX, Microsoft 365, etc.) in one apply.
## Balance and funding
Each org has a prepaid **balance** in AUD cents. Registrations and renewals debit the balance. If `auto_topup_enabled` is on and the balance falls below the threshold, we charge the saved card to refill.
A **transaction** is an immutable ledger row — top-up, debit, refund, adjustment. The balance is the running sum.
## API keys and scopes
A **key** is a bearer token (`dg_live_...` or `dg_test_...`) with one or more **scopes**. A scope is a verb on a resource: `domains:read`, `dns:write`, `contacts:write`, etc. A key with `dns:read` cannot edit DNS, even for a domain it can see.
Scopes are checked at the interface layer (the MCP tool body, the API route handler). The shared business logic underneath trusts its inputs.
## Confirmations (agent actions)
Anything an AI agent does that spends money or makes a bulk change runs through the **confirmation pipeline**. If the action exceeds the user's threshold or involves ≥5 items, the response is `status: "pending_confirmation"` with a token and an approval URL. The user approves out-of-band; the agent retries the call with the same `request_id` to execute.
It's the thing that stops an over-eager assistant from registering 200 domains because you said "and a few alternates".
## TLDs and eligibility
Australian (`.au`) TLDs have registry eligibility rules — `.com.au` and `.net.au` need an ABN/ACN and a name that matches it; `.id.au` is for individuals; `.org.au` for non-profits. We pass eligibility data to the registry on your behalf. Use `get_tld_info` (MCP) or `GET /pricing/{tld}` (API) for the current rules.
## Sync
State you change locally — auto-renew, contact assignments, privacy — is queued and applied to the registrar on the next **sync** cycle, not synchronously. Some changes (registration, renewal, DNS records) are synchronous; the docs note which.
---
# Buy a domain
Search, check availability, and register through the dashboard or the API.
URL: /guides/buying-a-domain
## In the dashboard
Open [`/search`](https://app.domaingenius.com.au/search) and type a name. Results stream in as alternative TLDs and AI-suggested variants come back.
Each result shows the year-1 price and renewal price. `.com.au` shows an eligibility hint if your org doesn't have an ABN on file yet.
For `.au`, paste your ABN. We verify it against the ABR before the registry call.
The cost debits your prepaid balance. If the balance is short and auto-top-up is on, your card is charged for the shortfall. The domain is live within seconds.
## Via the API
```bash
# 1. Check availability
curl "https://api.domaingenius.com.au/api/v1/domains/availability?domain=hello-world.com.au" \
-H "Authorization: Bearer $DG_KEY"
# 2. Register
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/hello-world.com.au/register" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{"years": 2}'
```
For `.au`, include `eligibility_id` (from `POST /v1/orgs/{org_oid}/contacts/eligibility`) in the body.
## Via MCP
Ask your assistant: "register hello-world.com.au under org Acme for 2 years". It calls `register_domains`. If the cost exceeds your threshold the response is `pending_confirmation` — approve in the browser, then say "go ahead" so the assistant retries with the same `request_id`.
## Things that can go wrong
| Error | Why | Fix |
| --- | --- | --- |
| `INSUFFICIENT_BALANCE` | Balance too low, auto-top-up off | Top up or enable auto-top-up |
| `INELIGIBLE` | `.au` ABN/ACN didn't match registry record | Check the ABR record and rerun |
| `REGISTRY_TIMEOUT` | Registry slow or down | Retry with same `Idempotency-Key` |
| `PRICE_CHANGED` | Quoted price differed from registry | Re-quote with `GET /pricing/{tld}` and retry |
---
# Transfer a domain in
Bring a domain registered elsewhere over to DomainGenius.
URL: /guides/transferring-in
A transfer-in moves a domain from another registrar to us. It does not change DNS or zone data — that comes along for the ride.
## Prereqs at the losing registrar
Find the registrar lock setting and turn it off.
Some registrars hide it three menus deep. The code is a short string of letters and digits — copy it exactly, including case.
The transfer approval email goes to the registrant or admin contact email on file. Make sure it's an inbox you can read.
Some TLDs (notably `.com`, `.net`) reject transfers with privacy on. Turn it off until the transfer completes; we re-enable it after.
## Start the transfer
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/transfer" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com", "auth_code": "..."}'
```
The transfer cost is one year of registration — we extend the existing expiry by 12 months. You don't lose time.
## Approval window
ICANN rules: the registrant has up to 5 days to approve via the email link. Most transfers finish in under an hour once approved; some TLDs (`.com.au`) finalise in seconds.
Track status with `GET /v1/orgs/{org_oid}/domains/transfers` or by listing pending confirmations.
## After the transfer
- Auto-renew defaults to **on**. Disable per-domain if you'd rather not.
- Contacts are imported as a single registrant record; fan it out into admin/tech/billing roles via [contacts](/guides/contacts-and-whois).
- DNS is unchanged — same nameservers, same records, even though the registrar field flipped.
## ICANN 60-day lock
Newly registered or recently transferred gTLDs are locked for 60 days at the registry. You can move them again after the lock expires. `.au` domains have no equivalent restriction.
---
# Manage DNS records
Add, update, and delete A, AAAA, CNAME, MX, TXT, and other records on a managed zone.
URL: /guides/dns-records
DNS for managed domains lives on Cloudflare. The zone is created when you enable managed DNS — either at registration time or via [`POST /v1/orgs/{org_oid}/domains/{domain}/dns/enable`](/api/org-domains).
## List records
```bash
curl "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns" \
-H "Authorization: Bearer $DG_KEY"
```
## Add a record
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "example.com.au",
"content": "203.0.113.10",
"ttl": 1,
"proxied": true
}'
```
`ttl: 1` means "auto" (Cloudflare-managed). Set a real TTL only if you need a specific value — the default is fine for most cases.
`proxied: true` runs the record through Cloudflare's proxy (CDN, DDoS, free TLS). Set to `false` for records that need to expose the origin IP (mail servers, certain SaaS integrations).
## Common record types
| Type | What it points to | Notes |
| --- | --- | --- |
| `A` | IPv4 address | The default for web traffic |
| `AAAA` | IPv6 address | Pair with A for dual-stack |
| `CNAME` | Another hostname | Cannot be used at the apex on most providers; use ALIAS or flattening |
| `MX` | Mail server hostname | Set `priority` (lower = preferred) |
| `TXT` | Arbitrary string | SPF, DKIM, domain verification |
| `NS` | Nameserver | Only set on subdomain delegations |
| `SRV` | Service host:port | Set `priority` and `weight` |
## CNAME at the apex
You can't have a CNAME at `example.com.au` because the apex must answer authoritatively. Cloudflare flattens CNAMEs at the apex by resolving them at request time — so a CNAME `example.com.au → cname.vercel-dns.com` actually works on a managed zone, even though it's technically a flattened A. If the receiving provider doesn't support flattening, use the [Vercel preset](/guides/dns-presets) or set explicit A records.
## Verify
```bash
dig example.com.au @1.1.1.1
```
Cloudflare propagates DNS changes globally in seconds. If `dig` shows stale data, your local resolver is caching — try `dig +short @1.1.1.1` to bypass.
---
# Apply a DNS preset
One-click templates for Vercel, Google Workspace, Microsoft 365, and other common providers.
URL: /guides/dns-presets
A preset is a bundle of records that one apply will configure a known service. Applying a preset:
1. Lists the records the preset wants.
2. Deletes any conflicting records on your zone.
3. Creates the new records.
Presets always confirm — even if the cost is zero, applying one is a bulk operation.
## List presets
```bash
curl "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns/presets" \
-H "Authorization: Bearer $DG_KEY"
```
Currently shipped: `vercel`, `cloudflare_pages`, `google_workspace_mx`, `google_workspace_dkim`, `microsoft_365_mx`, `proton_mail`, `fastmail`, `netlify`, `github_pages`, plus a few SPF helpers.
## Apply
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns/presets/apply" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "preset": "vercel" }'
```
Some presets need inputs:
```json
{
"preset": "google_workspace_dkim",
"input_values": {
"selector": "google",
"public_key": "v=DKIM1; k=rsa; p=MIIB..."
}
}
```
## What's currently active
```bash
curl "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns/presets/active" \
-H "Authorization: Bearer $DG_KEY"
```
Detection is record-shape-based — if you've manually added records that match a preset, it'll show as active.
## Remove
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/dns/presets/remove" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "preset": "vercel" }'
```
Removes only the records that match the preset, not the whole zone.
## Stacking
Presets are designed to compose. You can have `google_workspace_mx` and `vercel` on the same zone — the MX records and the apex routing don't conflict.
Presets that conflict at apply time (e.g. two MX-providing presets) will fail with `PRESET_CONFLICT`. Remove the existing one first.
---
# Contacts and WHOIS
Manage the registrant, admin, technical, and billing contacts on your domains.
URL: /guides/contacts-and-whois
Every registered domain carries up to four contact roles. Some TLDs require all four; some accept a single contact mapped to every role. Either way, you maintain a small library of contact records and assign them to domains.
## Create a contact
In the dashboard: [Contacts → New](https://app.domaingenius.com.au/dashboard/contacts).
Via API:
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/contacts" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Smith",
"organisation": "Acme Pty Ltd",
"address_one": "123 Example St",
"suburb": "Surry Hills",
"state": "NSW",
"country": "AU",
"postcode": "2010",
"phone": "+61.412345678",
"email": "jane@acme.example"
}'
```
Phone is in [E.164-with-dot](https://www.icann.org/resources/pages/contact-information-2014-02-22-en) format — country code, dot, number. ICANN spec, not us.
## Assign to a domain
```bash
curl -X PUT "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/contacts/registrant" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "contact_id": "..." }'
```
Roles: `registrant`, `admin`, `technical`, `billing`. Send the same contact to all four with `POST .../contacts/copy-registrant`.
## WHOIS privacy
Toggle `privacy: true` on the domain to redact contact info from public WHOIS lookups, replacing it with a forwarding address.
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "privacy": true }'
```
Privacy is **not available** on `.com.au`, `.net.au`, or `.org.au` — the .au registry mandates public WHOIS for accountability. The toggle is silently ignored on those TLDs. Privacy is available and on-by-default on `.com`, `.net`, `.org`, `.io`.
## Sync to the registrar
Local changes are pushed on the next sync cycle. To force it:
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/contacts/sync" \
-H "Authorization: Bearer $DG_KEY"
```
The sync call is idempotent — call it as often as you like.
---
# URL forwarding and redirects
Forward a domain to another URL with optional path forwarding and priority rules.
URL: /guides/redirects
There are two redirect models on DomainGenius:
- **Single redirect** (`update_domain_settings.redirect_url`) — sends every request to one target URL. Easy, no rules.
- **Per-path rules** (`/v1/domains/{domain}/redirects`) — rule list with patterns and priority. Useful for multi-path migrations.
Both run on Cloudflare Workers at the edge — sub-50ms TTFB worldwide.
## Single redirect
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/old-brand.com.au" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "redirect_url": "https://new-brand.com.au" }'
```
Path is preserved by default — `old-brand.com.au/about` becomes `new-brand.com.au/about`. Set `redirect_url` to an empty string to remove.
## Path-based rules
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/domains/old-brand.com.au/redirects" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{
"match": "/blog/*",
"destination": "https://new-blog.com/$1",
"status": 301
}'
```
`$1`, `$2`, ... refer to glob captures. Order rules with `PATCH /priorities`:
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/domains/old-brand.com.au/redirects/priorities" \
-d '{ "order": ["redir_001", "redir_002", "redir_003"] }'
```
Lowest-index rule that matches wins. Catch-all rule should be last.
## 301 vs 302
`301` (permanent) is cached aggressively by browsers — once a user has hit the redirect, their browser may not check back for months. Use it when you've decided. `302` (temporary) is not cached — use it during a migration window where you might roll back.
## What you can't do
- Redirect with a request body intact — redirects are always GET-after-redirect.
- Forward to a non-http(s) URL.
- Add custom headers on the redirected response.
For those cases, point the domain at your own server with a CNAME and handle the redirect there.
---
# Park a domain or list it for sale
Configure a parked landing page or put a domain on the marketplace with a minimum offer.
URL: /guides/parking-and-for-sale
A **parked** domain shows a configurable landing page — useful while you're sitting on a name, or testing positioning. A **for-sale** domain shows a "make an offer" page that funnels leads to your inbox via the DomainGenius marketplace.
You can run both at once. The for-sale CTA can sit on top of any parked template.
## Park
```bash
curl -X PUT "https://api.domaingenius.com.au/api/v1/domains/example.com.au/parked" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "minimal-coral",
"headline": "Coming soon",
"show_logo": true
}'
```
Templates: `minimal-coral` (default), `minimal-dark`, `coming-soon`, `under-construction`. Each renders at the apex; a wildcard A record + Worker handles the request.
## List for sale
```bash
curl -X PUT "https://api.domaingenius.com.au/api/v1/domains/example.com.au/for-sale" \
-H "Authorization: Bearer $DG_KEY" \
-d '{
"min_offer_cents": 50000,
"buy_now_cents": 250000
}'
```
`min_offer_cents` is what shows on the page. Lower offers are silently rejected by the form. `buy_now_cents` is optional — if set, a Buy Now button appears that takes payment instantly.
The domain shows up on the [DG marketplace](https://domaingenius.com.au/market) and in `GET /api/v1/market`.
## Receive offers
Offers come in via two channels:
- Email to the org's billing contact.
- The dashboard at [`/dashboard/domains//offers`](https://app.domaingenius.com.au/dashboard).
Negotiation happens in-thread. Accept an offer; we charge the buyer's card, transfer the domain into a new org under their account, and send you the proceeds (minus 5% marketplace fee) on the next payout.
## Unlist
```bash
curl -X DELETE "https://api.domaingenius.com.au/api/v1/domains/example.com.au/for-sale" \
-H "Authorization: Bearer $DG_KEY"
```
The marketplace listing disappears immediately. In-flight offers stay open until you decline them.
---
# Renewals and auto-renew
Stop a domain from expiring — manually, automatically, or both.
URL: /guides/renewals-and-auto-renew
Domains don't last forever. Each registration has an expiry; renewing extends it.
## Auto-renew (recommended)
Toggle on a single domain:
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "auto_renew": true }'
```
We attempt the renewal **30 days before expiry**, again at 14 days, and again at 7. The cost debits the org balance; if the balance is short, auto-top-up runs first. A failed renewal triggers an email and a webhook (`domain.expiring.7d`).
Auto-renew is **on by default** on every domain we register. Newly transferred-in domains inherit the previous registrar's setting, which is usually off — re-enable.
## Renew now
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au/renew" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "years": 2 }'
```
Most TLDs allow renewing for up to 10 years total (registry limit). The maximum extension is `max_period_years - current_period`. Use `GET /pricing/{tld}` for the cap.
## Grace and redemption
| Window | What happens | Recovery cost |
| --- | --- | --- |
| 0–30 days post-expiry | Domain enters **renewal grace** at the registry. Still resolvable on most TLDs. | Standard renewal price |
| 30–60 days post-expiry | **Redemption period**. Domain stops resolving. | Renewal + redemption fee (varies by TLD; ~$120 AUD for `.com`) |
| 60+ days post-expiry | **Released to pool**. Anyone can register it. | Open auction or standard registration |
Different TLDs use different windows — `.com.au` has a 30-day grace, no formal redemption. `.com` has 30-day grace + 30-day redemption. The `state` field on a domain reflects which window it's in.
## Bulk renew
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/renew-bulk" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "domains": ["a.com.au", "b.com.au", "c.com.au"], "years": 1 }'
```
Bulk renew always confirms when called from MCP/agent, never confirms when called from a key — the key holder is presumed to have authority.
## What happens at expiry, by source
- **Expired with auto-renew on, balance OK** — quietly renewed. No notification beyond the billing-contact receipt.
- **Expired with auto-renew on, balance short, auto-top-up off** — `domain.expiring.7d` webhook fires; the dashboard flags the domain. Renewal stops if not paid.
- **Expired with auto-renew off** — `domain.expiring.30d` and `.7d` webhooks fire; an email goes to the registrant and admin contacts.
---
# Estimate a domain's value
Run a domain through DomainGenius's valuation model for a market-comp-backed price.
URL: /guides/valuation
Valuation gives you a fair-market estimate for a domain — what someone might reasonably pay for it on the secondary market. Useful when you're considering an aftermarket purchase, listing your own, or appraising a portfolio.
## Get an estimate
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/valuation/estimate" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "domain": "shoes.com" }'
```
```json
{
"valuation_id": "val_01HF82YV...",
"domain": "shoes.com",
"estimate_aud": 4500000,
"low_aud": 2800000,
"high_aud": 7200000,
"confidence": 0.71,
"factors": [
{ "feature": "exact_match_keyword", "weight": 0.42 },
{ "feature": "comparable_sales", "weight": 0.31 },
{ "feature": "domain_age", "weight": 0.09 }
]
}
```
Estimates are AUD cents. The model returns a point estimate plus a confidence interval; treat the range, not the point, as the answer.
## What goes into the model
- **Exact-match keyword** — search volume + commercial intent (DataForSEO).
- **Comparable sales** — historical aftermarket sales of similar names (NameBio, GoDaddy DNJournal).
- **Backlinks and traffic** — Wayback historical traffic + a Moz/Ahrefs blend for live domains.
- **Length, brandability, TLD** — heuristic features.
- **Trademark risk** — flagged separately; doesn't lower the price but blocks resale.
The full feature set and weights are in the response under `factors`.
## Bulk
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/valuation/estimate" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "domains": ["a.com", "b.com", "c.com"] }'
```
Returns one object per domain. Bulk requests run async — the response gives you a job id; poll or subscribe to the `valuation.completed` webhook.
## Feedback loop
Got a sale price for a domain we appraised? Send it back:
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/valuation/$VAL_ID/feedback" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "actual_aud": 3000000, "context": "auction sale" }'
```
We retrain monthly. Your feedback shifts our priors on the comp set.
## Limits and caveats
- Estimates are **not** a guarantee of sale price. Real sales depend on specific buyers and timing.
- The model is biased toward English-language `.com`. Coverage on `.com.au` is solid; long-tail ccTLDs are best-effort.
- Domains with legal exposure (active trademark, prior UDRP) get a `trademark_risk` flag and we recommend you don't list them.
---
# Bulk search and batch availability
Check thousands of names at once via bulk endpoints and the streaming search API.
URL: /guides/bulk-search
When you're hunting names at scale — auctions, brand protection, name generation — single-domain calls add up. Two endpoints handle volume.
## `POST /domains/availability/bulk`
Up to 1,000 domains per request. Synchronous; returns when every domain has been resolved.
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/domains/availability/bulk" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "domains": ["a.com", "b.com", ..., "zzz.com"] }'
```
Cached results return instantly; uncached names are resolved against the registry in batches of 30 with backoff between batches. Expect ~10s for 1,000 fully uncached `.com` domains.
## Search stream
```bash
curl "https://api.domaingenius.com.au/api/v1/domains/search/stream?q=footwear&tlds=com,com.au,net" \
-H "Authorization: Bearer $DG_KEY" \
-H "Accept: text/event-stream"
```
Server-sent events. The stream emits:
```
event: result
data: {"domain": "footwear.com", "available": false, ...}
event: result
data: {"domain": "footwear.com.au", "available": true, "register_price_aud": 24.95, ...}
event: suggestion
data: {"domain": "footwearco.com.au", "available": true, "score": 0.78}
event: done
data: {"total": 47}
```
Suggestions come from an LLM seeded on the input plus the org's prior registrations. They're best-effort — discard ones that don't fit your taste.
## Pricing
Bulk and search count against your `bulk` rate-limit pool, not the interactive pool. See [Rate limits](/api/rate-limits).
## CSV input
For repeated jobs (brand monitoring), upload a CSV in the dashboard at [`/dashboard/tools/bulk-check`](https://app.domaingenius.com.au/dashboard/tools/bulk-check). Results download as a CSV with cached/source/price columns. Same engine, different glue.
---
# Organisations and members
Create orgs, invite teammates, set roles.
URL: /guides/organizations
Every action in DomainGenius runs in the context of an organisation. Domains, contacts, balance, and audit logs all live on the org, not the user.
## Solo accounts
Sign-up creates a default org for you. You can stay there forever — no penalty for never adding members. The org's slug and name become editable once you decide.
## Multi-tenant accounts
Add an org per client, project, or business unit. Each org has its own balance, billing, and domain list. Users move between orgs from the dashboard switcher.
## Create an org
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs" \
-H "Authorization: Bearer $DG_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme", "slug": "acme" }'
```
The slug must be unique across the platform. Check first with `GET /v1/orgs/check-slug?slug=acme`.
## Invite a member
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/members" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "email": "teammate@example.com", "role": "admin" }'
```
The invitee gets an email with a sign-in link. If they don't have a DomainGenius account, the same flow signs them up. Pending invites expire in 7 days.
## Roles
| Role | Can do |
| --- | --- |
| `owner` | Everything. There must be at least one owner. |
| `admin` | Everything except deleting the org or transferring ownership. |
| `member` | Read everything; trigger no state changes. Useful for read-only audit accounts. |
Change a role with `PATCH /v1/orgs/{org_oid}/members/{user_oid}`.
## Transfer ownership
Owner-only. From the dashboard: [`/dashboard/settings/danger-zone`](https://app.domaingenius.com.au/dashboard). The new owner gets an acceptance email; until they accept, both of you are owners.
## Delete an org
Owner-only, requires zero registered domains. Move or delete domains first. Deleting refunds any unspent balance to the original payment method.
---
# Create and rotate API keys
Mint, scope, and revoke keys for scripts and CI.
URL: /guides/api-keys
API keys are durable bearer tokens. They never expire — kill them when you're done.
## Mint
[Dashboard → API keys → New key](https://app.domaingenius.com.au/dashboard/api-keys).
Or via the API itself:
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/me/api-keys" \
-H "Authorization: Bearer dg_live_existingkey..." \
-H "Content-Type: application/json" \
-d '{
"name": "ci-deploy",
"scopes": ["domains:read", "dns:write"]
}'
```
```json
{
"id": "key_01HF82YV...",
"name": "ci-deploy",
"scopes": ["domains:read", "dns:write"],
"key": "dg_live_2k8n4j7s9..."
}
```
`key` is the full secret — only returned in this response, never again. Save it to a secrets manager.
## Scope tightly
A CI key that only updates DNS doesn't need `billing:write`. The dashboard pre-fills sensible scope sets per use case (CI, monitoring, registrar tooling) — start there.
## List
```bash
curl "https://api.domaingenius.com.au/api/v1/me/api-keys" \
-H "Authorization: Bearer $DG_KEY"
```
Responses show the prefix (`dg_live_2k8n…`) and metadata, never the secret.
## Rotate
There's no rotate endpoint. Mint a new key, deploy, delete the old one:
```bash
curl -X DELETE "https://api.domaingenius.com.au/api/v1/me/api-keys/$KEY_ID" \
-H "Authorization: Bearer $DG_KEY"
```
Deletion is immediate. Requests with the deleted key get HTTP 401 within seconds.
## Test mode
`dg_test_` keys hit the same routes but never call the registrar. Use them in CI fixtures so a passing test never accidentally registers `dxnghhg-test-1234.com`. Test keys can register, renew, transfer, and edit DNS — all returning synthetic confirmations.
Mint a test key from the dashboard with the **Test mode** toggle on.
## Leak protection
We scan public GitHub for `dg_live_` keys. If we find a match we revoke and email you. There's no way to opt out — leaked keys are leaked keys.
---
# Billing and balance
Top up the prepaid balance, set auto-top-up, and download invoices.
URL: /guides/billing-and-balance
DomainGenius runs on a prepaid balance. Registrations, renewals, and transfers debit the balance. There's no per-action card charge in the steady state.
## Top up
[Dashboard → Billing → Top up](https://app.domaingenius.com.au/dashboard/billing). Pick an amount, pay with card.
Via API:
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/billing/deposit" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "amount_cents": 10000 }'
```
The response carries a Stripe checkout URL — open it for the user.
## Auto-top-up
Configure in the dashboard or:
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/billing/auto-topup" \
-H "Authorization: Bearer $DG_KEY" \
-d '{
"enabled": true,
"threshold_cents": 5000,
"amount_cents": 20000
}'
```
Once the balance drops below `threshold_cents`, we charge the saved default card for `amount_cents`. Failed charges trigger `balance.low` webhooks and an email.
## Default card
Add or update via the Stripe billing portal:
```bash
curl -X POST "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/billing/portal" \
-H "Authorization: Bearer $DG_KEY"
```
The response has a portal URL. Card data never touches our servers — Stripe holds the PAN; we hold a payment method id.
## Transactions and invoices
```bash
curl "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/billing/transactions?limit=50" \
-H "Authorization: Bearer $DG_KEY"
```
Each row is an immutable ledger entry — top-up, debit, refund, adjustment. Sum the column to derive the balance.
Tax-compliant invoices for top-ups are PDFs available from the dashboard. We're GST-registered in Australia; invoices include ABN and tax breakdown.
## Refunds
Failed registrations refund automatically — the debit ledger row is paired with a same-amount credit. You'll see both rows in the transaction list.
For voluntary refunds (e.g. you topped up and changed your mind), email [billing@domaingenius.com.au](mailto:billing@domaingenius.com.au). We refund unspent balance to the original payment method, less any Stripe fees we paid.
---
# Configure webhooks
Subscribe an HTTPS endpoint to domain lifecycle and billing events.
URL: /guides/webhooks
Webhook setup is in the dashboard. Configure once; subscribe to the events you care about. The full event list is in the [API webhooks reference](/api/webhooks).
## Add an endpoint
[Dashboard → Settings → Webhooks](https://app.domaingenius.com.au/dashboard/settings/webhooks).
Public HTTPS URL. We won't post to plain HTTP.
All-or-individual. Start narrow.
Shown once. Used to verify each request — see [API webhooks](/api/webhooks#verify-the-signature).
The dashboard's **Send test event** button posts a synthetic `domain.registered` with `id: evt_test_...`. Useful for verifying your handler before any real event lands.
## What to do in your handler
- Verify the signature first. Reject unsigned requests.
- Read the event id and check for duplicates — we may retry, and a network blip can cause re-delivery after you 200'd. Build idempotency on `event.id`.
- Enqueue the work and return 200 quickly. Long handlers cause timeouts and retries.
## Local development
ngrok or a Cloudflare quick tunnel works. The dashboard accepts any public HTTPS URL.
```bash
ngrok http 8787
# Set webhook URL to the ngrok https URL
```
The dashboard shows recent deliveries with response codes. Bad endpoints get exponential backoff (30s → 24h) and pause after 24h of failures.
## Replay
Need to re-deliver a missed event? In the dashboard, open the event detail and click **Replay**. The endpoint receives the original payload with the same `id` — your idempotency layer should treat it as a no-op or proceed depending on intent.
## Internal webhooks
The endpoints under `/api/v1/webhooks/stripe` and `/api/v1/webhooks/clerk` are inbound — Stripe and Clerk POST to us. They are not user-configurable.
---
# Registration FAQ
Common questions about registering a domain.
URL: /faq/registration
## How long does registration take?
For most TLDs, seconds. The registry call returns a confirmation; the domain resolves once DNS propagates (also seconds with our managed DNS). `.com.au` is typically under five seconds end-to-end. `.com` and other gTLDs can take up to a minute on rare occasions when the registry queue is backed up.
## What's the minimum/maximum registration period?
Per TLD. Most allow 1–10 years. Some `.au` TLDs require a minimum of 2 years; `.id.au` allows 1. We expose the bounds via `get_tld_info` and `GET /pricing/{tld}` so you can check before the call.
## Can I register a domain for someone else?
Yes — register it under your org, then assign their details as the registrant contact. To hand over ownership, transfer the domain to their org via the dashboard's **Transfer to org** flow, or push it to a different registrar entirely.
## What happens if someone else registers the domain seconds before me?
Registry is first-come first-served. We pass your request to the registry as fast as the network allows; if the other request lands first, you get `NOT_AVAILABLE` and we don't bill. There is no queue or reservation system at the registry — there's no way to "hold" a name.
## Is bulk registration cheaper?
Per-domain price is the same. We don't have volume tiers — registry costs are flat. Bulk operations are free of UI overhead, not free of registry fees.
## Why did my registration fail?
The most common failure modes:
| Code | What happened |
| --- | --- |
| `NOT_AVAILABLE` | Someone else got it first, or our cache was stale |
| `INELIGIBLE` | `.au` registry rejected the supplied ABN/ACN |
| `INVALID_NAMESERVERS` | Custom NS list was malformed (you only hit this if you supplied your own) |
| `REGISTRY_TIMEOUT` | Registry slow to respond — retry safely with the same `Idempotency-Key` |
| `INSUFFICIENT_BALANCE` | Org balance too low and auto-top-up is off |
The `last_error` field on the failed domain row carries the registry's verbatim reason.
## Can I get a refund on a registration I made by mistake?
Most TLDs allow returns within 5 days of registration via the registry's "Add Grace Period" rule. Email [support@domaingenius.com.au](mailto:support@domaingenius.com.au) within 5 days; we return the registration and credit your balance for the registry fee minus a small handling fee. After 5 days, registrations are non-refundable — the registry has already taken the money.
## What about premium domains?
Some gTLDs (`.io`, `.ai`, `.app`) flag certain names as "premium" with elevated registry pricing. We surface premium prices in availability responses with `register_price_aud` reflecting the actual cost. There's no separate auction or negotiation — you pay the listed price.
## Do I own the domain?
You own the registration — the right to use the domain for the period you paid for. Registries operate on a leasehold model: there's no "freehold" for domains. As long as you renew, the registration persists indefinitely.
## What's the difference between buying via DomainGenius and buying via the registry directly?
You can't buy from the registry directly — registries (Verisign for `.com`, auDA's registry for `.au`) sell only through accredited registrars. We're an accredited reseller for Synergy Wholesale (auDA accreditation) and through ICANN-accredited upstreams for gTLDs.
---
# DNS FAQ
Common questions about DNS, propagation, and record types.
URL: /faq/dns
## How long does a DNS change take to propagate?
On our managed DNS (Cloudflare), authoritative servers receive the change in under five seconds. End-user resolvers cache previous answers up to the previous record's TTL — so if the old record had `ttl=3600`, some users may see stale data for an hour.
If a fast change matters, lower the TTL on the existing record several hours *before* the change. Then the change is fast.
## What's the difference between A and CNAME?
`A` points to an IP address. `CNAME` points to another hostname. Browsers and resolvers chase CNAMEs until they reach an A or AAAA.
You can't have a CNAME at the apex (`example.com.au`) on traditional DNS — the apex must answer authoritatively. Cloudflare-managed zones flatten apex CNAMEs by resolving them at request time, so `CNAME example.com.au → cname.vercel-dns.com` works on managed DNS even though it'd fail elsewhere.
## What's a TTL? What should I set it to?
TTL (time-to-live) is how long resolvers cache a record. Higher = less load, less responsive. Lower = more load, faster changes.
For most records, our default of **auto** (Cloudflare-tuned, usually around 300s) is right. Drop to 60s before a planned migration. Set 3600+ for stable infrastructure records that never change.
## What's the difference between proxied and DNS-only?
Proxied (orange cloud in Cloudflare terminology) routes traffic through Cloudflare's CDN — the client sees a Cloudflare IP, not your origin. You get caching, DDoS protection, and free TLS.
DNS-only (grey cloud) returns your origin IP directly. Use it for records that need the real IP exposed: mail (`MX`), some SaaS verifications (`TXT`), or origin-pull CDNs.
## My SPF/DKIM/DMARC records aren't working. Why?
The three most common causes:
1. **Multiple SPF records.** RFC says one TXT record beginning with `v=spf1`. Combine them.
2. **Quoted vs unquoted.** SPF and DKIM records contain `v=spf1` etc. Don't wrap in extra quotes — just paste the value verbatim into the `content` field.
3. **DKIM split incorrectly.** Long DKIM keys are split into 255-char segments separated by spaces. Our API accepts the full key as one string and chunks it correctly. If you've manually split it elsewhere, paste the full unsplit version.
## Can I move DNS away from DomainGenius without transferring the domain?
Yes. Update the domain's nameservers to point elsewhere (Route 53, Google Cloud DNS, your own BIND, whatever):
```bash
curl -X PATCH "https://api.domaingenius.com.au/api/v1/orgs/$DG_ORG/domains/example.com.au" \
-H "Authorization: Bearer $DG_KEY" \
-d '{ "nameserver_one": "ns1.elsewhere.com", "nameserver_two": "ns2.elsewhere.com" }'
```
The domain stays registered with us; DNS authority moves. You lose the convenience of managed DNS (presets, our API, our edge) but keep registration.
## What about DNSSEC?
Managed DNS zones get DNSSEC signed automatically — Cloudflare handles key rollover. The DS record at the registry is published on registration. To disable (rare — usually only for migration), email [support@domaingenius.com.au](mailto:support@domaingenius.com.au).
## Why does `dig` show different results from my browser?
Browsers and OSes have multiple cache layers (DNS resolver cache, browser cache, OS resolver cache). `dig +short @1.1.1.1` queries Cloudflare's public resolver directly, bypassing all of them. If `dig` is correct and the browser is wrong, flush:
- macOS: `sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder`
- Linux (systemd): `sudo systemd-resolve --flush-caches`
- Windows: `ipconfig /flushdns`
- Browser: hard reload, or restart.
## How many records can a single zone hold?
Practically: thousands. Cloudflare's plan-level limits start at 1,000 records and scale up. We don't add a layer on top.
## Can I import a zone from somewhere else?
Yes — paste a BIND zone file at [`/dashboard/domains//dns/import`](https://app.domaingenius.com.au/dashboard). Records are previewed before being applied. Imports are atomic — all or none.
---
# Transfers FAQ
Moving a domain in to or out of DomainGenius.
URL: /faq/transfers
## How long does a transfer take?
| TLD | Typical transfer time |
| --- | --- |
| `.com.au`, `.net.au` and other .au | Seconds to minutes (no FOA, registry-mediated) |
| `.com`, `.net`, `.org` and other gTLDs | Up to 5 days (registrant approval window) |
| Some ccTLDs | Up to 14 days |
Most gTLD transfers complete within an hour of approval. `.au` is near-instant once unlocked.
## Will I lose any registration time?
No. Transfers extend the existing expiry by 1 year — the cost is one year of registration, but you don't pay for time you already had.
Transfers within 30 days of expiry also cover the existing period — you won't lose the domain to expiry mid-transfer.
## Why was my transfer rejected?
The registry's response is in `last_error`. Common ones:
- **Registrar lock on.** Disable the lock at the losing registrar.
- **Wrong auth code.** Copy carefully — case matters, and some registrars include hidden whitespace in the copy buffer.
- **Domain registered or transferred within 60 days.** ICANN policy: gTLDs are locked from transfer for 60 days after creation or transfer. Wait it out.
- **WHOIS privacy on at the losing registrar.** Some registries reject privacy-protected transfers. Disable privacy first.
- **Registrant didn't approve in time.** ICANN gives 5 days. After expiry, restart the transfer.
## What's an EPP code / auth code / authorization code?
Three names for the same thing — a string the losing registrar provides that proves you authorise the transfer. Length and format vary by registry: some are 6-character alphanumerics, others are 16-character mixed-case strings with symbols.
You can't transfer without it. If your losing registrar is dragging their feet, ICANN policy compels them to provide it within 5 days of request.
## Can I cancel a transfer in progress?
Yes, until it completes. From the dashboard, find the pending transfer and click **Cancel**. The registry receives a `domain:transfer_cancel` and we credit any pre-paid amount back to your balance.
## What about transfers out of DomainGenius?
We don't lock you in. To move out:
[`/dashboard/domains/`](https://app.domaingenius.com.au/dashboard) shows the EPP code. Or via API: `GET /v1/orgs/{org_oid}/domains/{domain}` (requires `domains:write` scope).
Toggle `privacy: false` if it was on (and the TLD supports privacy in the first place).
Their flow takes over from there. We approve the transfer the moment the registry asks.
## Will I lose my DNS records when I transfer?
Transfers move registration, not DNS. Your records stay where they are.
If your zone is on our managed DNS and you transfer to a registrar that doesn't host the zone, you have two options: keep the zone on our nameservers (`nameserver_one`, `nameserver_two` point at our Cloudflare zone NS — works as long as we have the zone record) or export the zone and re-import elsewhere. We export to BIND format from the dashboard.
## What's the change-of-registrant lock?
ICANN policy: changing the registrant contact on a gTLD locks the domain from transfer for 60 days. The intent is to prevent ownership-then-transfer hijacks. We trigger this lock when you change the registrant, but only after the change has actually been confirmed by the registry — so a same-org reassignment that doesn't change registry-visible WHOIS data doesn't trigger it.
`.au` has no equivalent rule.
## Can I push a domain to another DomainGenius org without a registry transfer?
Yes — internal "push" doesn't touch the registry. Use the dashboard's **Move to org** flow or `POST /v1/orgs/{org_oid}/domains/{domain}/push`. The destination org accepts the push; ownership flips. No fees, no lock period.
---
# Pricing and billing FAQ
How DomainGenius charges, refunds, and bills.
URL: /faq/pricing-and-billing
## Why do TLDs cost different amounts?
Each registry sets a wholesale price for their TLD. Verisign's `.com` is around $11 USD wholesale; auDA's `.com.au` is around $14 AUD. Every registrar pays the same wholesale; differences in retail are margin.
We post a fixed retail markup over wholesale. Bulk volume doesn't change your price — the registry charges us per-domain regardless.
## Why does renewal cost more than registration sometimes?
Some registries discount the first year (introductory pricing) and charge more on renewal. `.io`, `.app`, and many newer gTLDs do this. Before registering a long-term holding, check the renewal price — `get_tld_info` and `GET /pricing/{tld}` show both.
## Are domains on DomainGenius cheaper than elsewhere?
For `.au`: usually yes, because we're a direct Synergy reseller. For gTLDs: comparable to other transparent registrars, more expensive than first-year-discount loss leaders. Our value isn't in the lowest one-year price; it's in transparent renewals, the API, and not surprising you with hidden fees.
We don't markup transfers — they cost the same as a one-year renewal.
## Why prepaid balance instead of charge-per-action?
Three reasons:
1. **Failure handling.** Card declines mid-renewal would lose domains. With balance, the renewal succeeds even if your card later fails — and we have time to fix the card before the next auto-top-up.
2. **Bulk operations.** Registering 100 domains as 100 separate card charges is a Stripe fee disaster. Top up once, debit 100 times.
3. **Refund clarity.** Failed registrations refund cleanly to the balance ledger. Card refunds take 5–10 business days.
## Can I get a refund?
Yes:
- **Failed registrations** — automatic. The debit ledger row pairs with a same-amount credit.
- **Wrong-domain registrations** — within 5 days of registration, email support. We return to the registry under their grace period and credit your balance, less a small handling fee for our time.
- **Unspent balance** — email [billing@domaingenius.com.au](mailto:billing@domaingenius.com.au). We refund to the original payment method, less Stripe fees.
- **Failed renewals** — refunded to balance automatically.
- **Voluntary expiries** — no refund. If you stopped auto-renew and the domain expired, that's working as designed.
## How does GST work?
We're GST-registered in Australia. Top-ups from Australian customers include 10% GST in the headline price; invoices break out the GST line and our ABN. International customers pay no GST.
The registry fees themselves are wholesale — you don't see the GST split inside a registration receipt, but it's in there.
## What about VAT for EU customers?
We're not VAT-registered in the EU. EU business customers handle reverse-charge VAT on their own returns. We supply invoices that comply with the EU's reverse-charge format.
## Can I pay by invoice instead of card?
For accounts above a certain spend threshold, yes — email [billing@domaingenius.com.au](mailto:billing@domaingenius.com.au). Invoice billing turns off auto-top-up; you pay 30 days net, balance is debited as you go. Works for everyone except renewals during the 30-day window — those still need balance up front.
## Do you take crypto?
No.
## Are there hidden fees?
No. The price you see in `pricing/{tld}` is what gets debited from your balance — same for registration, renewal, and transfer. The only out-of-band charge is the 5% marketplace fee on a successful for-sale transaction (visibly shown in the dashboard before you list).
## Why was my balance debited but the domain not registered?
Race conditions: we attempted registration, debit was committed, then the registry rejected the call (rare — usually `NOT_AVAILABLE` because someone got there first). The pending refund is reconciled within 60 seconds; you'll see the credit in the transaction list. If it's been more than 5 minutes, contact support.
---
# Security and privacy FAQ
How we protect accounts, data, and your domains.
URL: /faq/security-and-privacy
## What is WHOIS privacy and do I need it?
WHOIS is a public directory of domain registration data — owner name, address, email. Privacy replaces those fields with a forwarding service so spammers can't harvest them.
You probably want it on for personal `.com` / `.net` / `.org` domains. You can't have it on `.au` — registry policy mandates public WHOIS for all `.au` TLDs.
## Are my registration details public?
For TLDs that allow privacy, with privacy on: only your name and a forwarding address show up. Full record stays with us and the registry.
For TLDs without privacy (`.au` family, `.de`, `.fr`, others), full registrant data is public. EU GDPR led most registries to redact personal data in WHOIS responses by default for individuals; commercial registrants stay public.
## How do you store API keys?
We store the prefix (`dg_live_2k8n4j7s9...`'s first 12 chars) and an Argon2id hash of the rest. The full key never lives on our servers after we hand it back to you in the create response.
## What if I leak a key?
Revoke it at [`/dashboard/api-keys`](https://app.domaingenius.com.au/dashboard/api-keys). The deletion is immediate.
We also scan public GitHub commits for `dg_live_` patterns. Matches are auto-revoked and you get an email. Don't rely on us catching everything — review your secrets hygiene.
## Do you support MFA?
Yes — TOTP (any RFC 6238 authenticator app) and WebAuthn / passkeys. Add at [`/dashboard/security`](https://app.domaingenius.com.au/dashboard/security). For org owners we recommend WebAuthn — phishing-resistant, fast, no shared secret.
## Can someone steal my domain by guessing my password?
A password alone won't move a domain. State-changing operations from a logged-in session require:
- Recent re-auth (sensitive ops re-prompt for password or MFA).
- A confirmation step for transfers and contact changes (email link).
- An audit log entry visible to other org owners.
A stolen API key with `domains:write` could push a domain to another org you also own, but couldn't transfer it to a different registrar without the EPP code, which is only revealed in a `domains:write` `GET /domain` response — i.e. someone with the key still has it. Rotate keys regularly.
## What's the registry-lock?
A premium feature for high-value domains: the registry refuses to accept any change requests until you authenticate out-of-band (a phone call, a multi-party email confirmation). Locks transfers and DNS changes, not just transfers.
We support registry-lock for select TLDs (`.com`, `.net`, `.org`, `.com.au`). Email [support@domaingenius.com.au](mailto:support@domaingenius.com.au) to enable on a domain — we set up the out-of-band protocol once, then any sensitive op needs the lock-bypass step.
## Where is data stored?
Australia (primary) and Singapore (read replicas). DNS data lives on Cloudflare's global edge. We're not subject to US CLOUD Act demands.
## Are you SOC 2 / ISO 27001 certified?
ISO 27001 audit in progress (target Q4 2026). SOC 2 Type II planned for early 2027. We can share our security questionnaire, vendor risk doc, and DPIA on request.
## How do you handle data deletion requests?
Per Australian Privacy Principles and GDPR Article 17. Submit at [privacy@domaingenius.com.au](mailto:privacy@domaingenius.com.au) — we delete personal data within 30 days, retaining only what we're required to keep (transaction records under tax law, audit logs under registrar accreditation).
## Can I get a copy of my data?
Yes — request via [privacy@domaingenius.com.au](mailto:privacy@domaingenius.com.au). Within 30 days you get a JSON export of every record we hold under your user_id, plus a CSV of audit log events. Free, once per year; nominal fee for additional pulls.
---
# .au domains FAQ
Eligibility, registry rules, and quirks of the .au namespace.
URL: /faq/au-domains
## Who can register a `.com.au` or `.net.au`?
A registered Australian commercial entity. In practice that means you need:
- An ABN (Australian Business Number), **or**
- An ACN (Australian Company Number), **or**
- An RBN (Registered Business Name).
You also need a "close and substantial connection" between the registered entity and the domain name itself. The 2008 rule that required a literal name match was relaxed — a brand or product name owned by the entity is usually fine.
## Can a non-Australian entity register `.com.au`?
A non-Australian entity can apply if it holds a registered Australian trademark that matches the domain. The trademark needs to be granted (not pending) and active. Otherwise no — the registry will reject the application.
For everyone else, [direct `.au`](https://www.auda.org.au/au-domain-names/direct-au) (since 2022) requires Australian presence too — ABN/ACN for businesses, residency for individuals.
## What about `.org.au`?
Non-commercial Australian organisations: charities, associations, professional bodies, sporting clubs. ABN required for the organisation. The registry checks that the organisation type is non-commercial.
## What about `.id.au`?
Personal use. Australian citizens or permanent residents. No ABN required — your name on the registration is enough. The domain must relate to your personal identity (your name, a personal handle, a hobby).
## What about `.asn.au` and `.gov.au`?
`.asn.au` — Australian associations, sports clubs. Needs ABN.
`.gov.au` — Australian government bodies only. We don't sell `.gov.au`; it's restricted to government entities that apply directly to auDA.
## Can I have WHOIS privacy on `.au`?
No. auDA mandates public WHOIS for `.au` TLDs — name, address, email, and phone are public. Set the toggle to `privacy: true` and we silently ignore it on `.au`.
If your contact data needs to be hidden, use a registered address (e.g. an accountant's office) and a role-based email.
## How long is the renewal grace period?
`.au` registries give a 30-day renewal grace after expiry. After grace, the domain is **released** — there's no formal redemption period like `.com` has. This means once a `.au` domain has dropped, it's gone, and someone else can register it.
We send 30-day, 14-day, 7-day, and 1-day pre-expiry notifications. Auto-renew is on by default for everything we register.
## Can I transfer `.au` domains?
Yes. `.au` transfers are registry-mediated and near-instant once you've supplied the auth code. There's no 60-day lock like ICANN gTLDs — you can register a `.au` and transfer it elsewhere the same day if you want.
## Can I have multi-year registrations on `.au`?
Yes. `.com.au` and `.net.au` accept 1–5 year registrations (most TLDs allow up to 10, but `.au` policy caps it). Renewals can extend beyond the initial term, also up to 5 years.
## What's the deal with `.au` direct (no second-level)?
Since March 2022, anyone with Australian presence can register a name directly under `.au` (e.g. `example.au` instead of `example.com.au`). The application rules are identical to `.com.au`. Existing `.com.au` holders had a priority-allocation window in 2022; that's closed now.
## Why does my `.au` registration ask for an "eligibility id"?
The registry wants to verify the ABN/ACN. You upload it once via [`/v1/orgs/{org_oid}/contacts/eligibility`](/api/org-contacts), we verify against the ABR, and store the result. Future `.au` registrations reference the eligibility id rather than re-uploading the ABN every time.
## Can I register a name that infringes a trademark?
The registry doesn't pre-screen for trademarks (that's auDA's general rule), but auDA runs a [Dispute Resolution Policy (auDRP)](https://www.auda.org.au/au-domain-administration-rules-dispute-resolution) — the trademark holder can file a complaint, and you may lose the domain if the panel rules against you.
We surface a `trademark_risk` flag on valuations (and search results when the risk is high). Heed it.
## What does it cost compared to `.com`?
Wholesale `.com.au` is around $14 AUD/year; wholesale `.com` is around $16 AUD/year (varies with USD/AUD exchange). Retail at DomainGenius reflects the wholesale split — see [`/pricing`](https://domaingenius.com.au/pricing) for current numbers.
---
# API overview
HTTP JSON API for domain search, registration, DNS, billing, and account management.
URL: /api/introduction
The DomainGenius API is a REST/JSON service. Every state-changing request goes through the same code path the dashboard uses.
## Base URL
```
https://api.domaingenius.com.au
```
All endpoints live under `/api/v1`. There is no v0; breaking changes will ship as `/api/v2`.
## Format
- Request and response bodies are JSON.
- Timestamps are ISO 8601 in UTC (`2026-05-01T12:34:56Z`).
- Money is in cents, no currency mixing on a single endpoint.
- IDs are opaque strings — don't parse them.
## Authenticated requests
Send a bearer token. See [Authentication](/api/authentication).
```bash
curl https://api.domaingenius.com.au/api/v1/me \
-H "Authorization: Bearer dg_live_..."
```
## When to use the API vs MCP
Scripts, server-to-server, batch jobs, custom UIs.
Letting an AI assistant act on your account. See [MCP overview](/mcp/introduction).
Both interfaces wrap the same business logic. There is no API-only feature; there is no MCP-only feature.
---
# Authentication
Bearer tokens — Clerk session JWTs for browsers, API keys for scripts.
URL: /api/authentication
Every authenticated endpoint accepts a bearer token in the `Authorization` header.
```http
Authorization: Bearer
```
Two token types are accepted on the same header:
| Type | Prefix | Use for | Lives where |
| --- | --- | --- | --- |
| API key | `dg_live_` / `dg_test_` | Scripts, CI, server-to-server | Mint at [`/dashboard/api-keys`](https://app.domaingenius.com.au/dashboard/api-keys) |
| Session JWT | none | Browser SDK, dashboard | Issued by Clerk on sign-in |
The server picks the right verifier from the token shape. You don't pick.
## API keys
```bash
curl https://api.domaingenius.com.au/api/v1/me \
-H "Authorization: Bearer dg_live_2k8n4j..."
```
Keys carry scopes. A key with only `domains:read` cannot create a contact. See [API keys and scopes](/api/api-keys-and-scopes).
## Session JWTs
Browser SDKs lift the JWT off the Clerk session and send it on every request. You won't usually construct these by hand. If you're building a server-side companion that acts on behalf of a signed-in user, [exchange the JWT](https://clerk.com/docs/backend-requests/handling/manual-jwt) on your backend rather than passing it to your frontend.
## Org context
Endpoints under `/api/v1/orgs/{org_oid}/...` take the organisation OID in the path. The token must belong to a member of that org.
For non-org endpoints (`/api/v1/me`, `/api/v1/domains/availability`, etc.), the token alone identifies the caller.
## What happens when auth fails
```json
{ "detail": "Not authenticated" }
```
HTTP 401 means the token is missing, malformed, expired, or revoked. HTTP 403 means the token is valid but lacks the required scope or org membership. See [Errors](/api/errors).
---
# API keys and scopes
Mint keys, choose scopes, rotate, and revoke.
URL: /api/api-keys-and-scopes
API keys are durable bearer tokens prefixed `dg_live_` (production) or `dg_test_` (sandbox).
## Mint a key
Go to [API keys](https://app.domaingenius.com.au/dashboard/api-keys).
Select the scopes the key needs. Less is more — see the matrix below.
The full key is shown once. Store it in a secrets manager. We only keep the prefix and a hash.
You can also mint keys via the API itself — see [`POST /api/v1/me/api-keys`](/api/api-keys#create-api-key).
## Scope matrix
| Scope | What a key with this scope can do |
| --- | --- |
| `availability:read` | Check whether domains are registered |
| `domains:read` | List org domains, read settings, status, health |
| `domains:write` | Update auto-renew, redirects, privacy, sale status; renew; transfer |
| `dns:read` | List DNS records and active presets |
| `dns:write` | Create, update, delete DNS records; apply or remove presets |
| `contacts:read` | Read org contacts and per-domain contact assignments |
| `contacts:write` | Create, update, delete contacts; assign or unassign roles |
| `orgs:read` | Read org members and audit logs |
| `orgs:write` | Add or remove members; update org settings |
| `billing:read` | Read balance, transactions, invoices |
| `billing:write` | Top up balance, configure auto-top-up |
A request that needs a scope your key lacks gets HTTP 403 with `{ "detail": "Missing scope: dns:write" }`.
## Rotation
There is no expiry on a key. Rotate by minting a new key, deploying it, then deleting the old one in the dashboard. Deleted keys stop working immediately — there is no grace period.
## Test mode
`dg_test_` keys hit the same API but never call the registrar. Domain operations return synthetic confirmations. Use them in CI.
## Revocation triggers
A key is killed automatically if:
- The owning user is disabled.
- The key's last-used IP enters our abuse list.
- A duplicate key value appears in a public commit (we scan GitHub).
You'll get an email and the key flips to `revoked` in the dashboard.
---
# Errors
HTTP status codes and error body shape.
URL: /api/errors
Errors carry an HTTP status code and a JSON body.
```json
{
"detail": "Domain is locked at the registry",
"code": "DOMAIN_LOCKED"
}
```
`detail` is human-readable. `code` is a stable machine token; new codes can appear, existing ones don't change meaning.
## Status codes
| Code | When |
| --- | --- |
| 200 | OK |
| 201 | Resource created |
| 202 | Action accepted, work happens async (registration, transfer) |
| 204 | No content (delete) |
| 400 | Invalid input. Body has field-level detail under `detail` (FastAPI shape). |
| 401 | Missing or bad token |
| 402 | Payment required — balance too low for the action |
| 403 | Token valid but lacks scope or org access |
| 404 | Resource not found, or you don't have access (we don't leak existence) |
| 409 | Conflict — duplicate, version mismatch, or domain in incompatible state |
| 422 | Schema validation failed (FastAPI default) |
| 429 | Rate-limited — back off |
| 500 | Server bug. Always reportable. |
| 502 / 503 | Upstream registrar or DNS provider unavailable. Safe to retry with backoff. |
## Validation errors
FastAPI returns 422 with a list of field errors:
```json
{
"detail": [
{
"loc": ["body", "tld"],
"msg": "TLD must be lowercase",
"type": "value_error"
}
]
}
```
## Idempotency
State-changing endpoints accept an `Idempotency-Key` header. Sending the same key with the same body within 24 hours returns the cached response — safe to retry network failures without double-charging.
```bash
curl -X POST .../v1/orgs/org_x/domains/example.com/renew \
-H "Idempotency-Key: $(uuidgen)" \
-H "Authorization: Bearer dg_live_..."
```
A duplicate key with a different body returns HTTP 409.
---
# Rate limits
Per-key limits, headers, and how to recover from 429.
URL: /api/rate-limits
Rate limits are per API key (or per session for browser tokens), not per IP.
## Default limits
| Endpoint group | Limit | Burst |
| --- | --- | --- |
| Availability and search | 600 / minute | 60 / second |
| Read endpoints | 300 / minute | 30 / second |
| Write endpoints | 60 / minute | 10 / second |
| Bulk operations | 10 / minute | 2 / second |
Limits scale with your plan; if you need more, email [support@domaingenius.com.au](mailto:support@domaingenius.com.au).
## Headers on every response
```http
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1714560420
```
`X-RateLimit-Reset` is a Unix timestamp.
## When you hit a 429
```json
{ "detail": "Rate limit exceeded", "code": "RATE_LIMITED" }
```
The response carries `Retry-After` in seconds:
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
```
Sleep for `Retry-After` and retry. Don't retry sooner — repeat 429s widen your backoff multiplier.
## Burst recovery
If you have a large batch (a CSV of 50,000 domains, say), send it through `POST /api/v1/domains/availability/bulk` rather than fanning out individual GETs. Bulk endpoints have their own pool and don't compete with your interactive traffic.
---
# Pagination
Cursor-based pagination on list endpoints.
URL: /api/pagination
List endpoints return up to 100 items per page and a cursor for the next page.
## Request
```bash
curl "https://api.domaingenius.com.au/api/v1/orgs/org_x/domains?limit=50&cursor=eyJpZCI6..."
```
| Param | Default | Max |
| --- | --- | --- |
| `limit` | 25 | 100 |
| `cursor` | — | opaque string from a previous response |
## Response
```json
{
"items": [ /* up to limit */ ],
"next_cursor": "eyJpZCI6IjAxSDgyN1lWLi4uIn0=",
"has_more": true
}
```
`next_cursor` is `null` on the last page; `has_more` mirrors that. Don't parse the cursor — it's a base64 envelope and the schema can change.
## Loop pattern
```ts
let cursor: string | null = null;
do {
const url = new URL(`https://api.domaingenius.com.au/api/v1/orgs/${oid}/domains`);
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
const page = await res.json();
for (const domain of page.items) await handle(domain);
cursor = page.next_cursor;
} while (cursor);
```
## Stable ordering
List endpoints sort by creation time descending unless documented otherwise. New rows landing during pagination shift the cursor — you may see a row twice or miss it. If you need exact-once iteration, take a snapshot via `Idempotency-Key` or filter by a fixed `created_before`.
---
# Webhooks
Event delivery for domain lifecycle and billing changes.
URL: /api/webhooks
DomainGenius posts JSON events to your endpoint over HTTPS when something changes server-side — registration completing, balance dropping, a domain expiring soon.
## Configure
In the dashboard, go to [Settings → Webhooks](https://app.domaingenius.com.au/dashboard/settings/webhooks) and add an endpoint URL. Pick the events you care about. We sign every request.
## Events
| Event | Fires when |
| --- | --- |
| `domain.registered` | Registry confirms registration |
| `domain.transfer.started` | Transfer-in initiated, awaiting auth code |
| `domain.transfer.completed` | Transfer-in finished |
| `domain.expiring.30d` / `.7d` / `.1d` | Domain expiry within window, no auto-renew |
| `domain.expired` | Past expiry |
| `domain.deleted` | Registry-deleted (after grace) |
| `dns.changed` | A record was created, updated, or deleted |
| `balance.low` | Org balance dropped below the auto-top-up trigger |
| `invoice.paid` | Top-up or subscription invoice paid |
## Payload shape
```json
{
"id": "evt_01HF82...",
"type": "domain.registered",
"created": "2026-05-01T08:42:00Z",
"data": {
"domain": "example.com.au",
"org_oid": "org_01HF80...",
"expires_at": "2027-05-01T00:00:00Z"
}
}
```
## Verify the signature
Every request carries `DG-Signature: t=,v1=`:
```ts
import crypto from "node:crypto";
const verify = (raw: string, header: string, secret: string) => {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${raw}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
};
```
Reject requests where `t` is older than five minutes; that's the replay window.
## Retries
We retry non-2xx responses with exponential backoff: 30s, 2m, 10m, 1h, 6h, 24h. After 24h of failures the endpoint is paused and you get an email.
Respond `200 OK` as soon as you've durably enqueued the event. Long handlers cause timeouts and retries.
## Inbound webhooks
The endpoints under `/api/v1/webhooks/stripe` and `/api/v1/webhooks/clerk` are inbound — Stripe and Clerk POST to us. They are not configurable from your side and not part of the public API surface.
---
# MCP overview
Connect AI assistants to DomainGenius via Model Context Protocol.
URL: /mcp/introduction
The DomainGenius MCP server lets an AI assistant search availability, register domains, edit DNS, and manage your account. Works with Claude, Cursor, Windsurf, Zed, and any MCP client that speaks streamable HTTP.
## Endpoint
```
https://mcp.domaingenius.com.au/mcp
```
Transport: streamable HTTP (the FastMCP 2.x default). The server is stateless; each request authenticates independently.
## What you can do
Six tool families, mapping one-to-one with the API:
- [Availability](/mcp/tools/availability) — check domains, look up TLDs.
- [Domains](/mcp/tools/domains) — list, inspect, update settings.
- [DNS](/mcp/tools/dns) — read and write records, apply presets.
- [Contacts](/mcp/tools/contacts) — registrant, admin, tech, billing.
- [Orgs](/mcp/tools/orgs) — discover org membership and members.
- [Registration](/mcp/tools/registration) — register, renew, balance, confirmations.
## Safety: confirmations
Spending money or doing bulk operations always confirms. If your assistant tries to register five domains in one call, or any single charge above your threshold, the tool returns `status: "pending_confirmation"` with an approval URL. You approve in the browser; the assistant retries with the same `request_id` to execute. Set thresholds at [`/dashboard/settings/agent`](https://app.domaingenius.com.au/dashboard/settings/agent).
## Pick a client
Cline users — see [Cline](/mcp/install/cline). Any MCP-compatible client that speaks streamable HTTP and bearer auth will work; copy the JSON block from any of the editor pages.
---
# MCP authentication
Two ways to authenticate — Clerk OAuth or an API key.
URL: /mcp/authentication
The MCP server accepts two token types on the same `Authorization: Bearer ...` header. The server picks the right verifier from the token shape — you don't.
## Option 1: Clerk OAuth (recommended)
For interactive use. Most MCP clients trigger this flow automatically the first time they call the server: a browser tab opens, you sign into your DomainGenius account, pick the org, and approve the requested scopes. The client stores the resulting access token.
When the token expires, the client silently refreshes it. Revoke a session at [`/dashboard/sessions`](https://app.domaingenius.com.au/dashboard/sessions).
## Option 2: API key
For headless use, CI, or when your client doesn't support OAuth. Mint a key at [`/dashboard/api-keys`](https://app.domaingenius.com.au/dashboard/api-keys), add it to the client config:
```json
{
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
```
The exact JSON shape varies by client — see the install pages.
API keys carry per-key scopes. OAuth sessions get the default agent scope set:
| Scope | Granted to OAuth | Granted to keys |
| --- | --- | --- |
| `availability:read` | yes | only if minted with it |
| `orgs:read`, `orgs:write` | yes | only if minted |
| `domains:read`, `domains:write` | yes | only if minted |
| `dns:read`, `dns:write` | yes | only if minted |
| `contacts:read`, `contacts:write` | yes | only if minted |
| `billing:read`, `billing:write` | no — must use a key | only if minted |
Billing actions are deliberately out-of-scope for OAuth — top-ups go through the dashboard or a key, not the assistant.
## Failures
```json
{ "error": { "code": -32001, "message": "Missing scope: dns:write" } }
```
Code `-32001` is auth-related (missing or revoked token, missing scope, missing org membership). Mint a wider key or sign in to a different org.
---
# MCP scopes
Per-tool scope requirements — what your token needs to call what.
URL: /mcp/scopes
Every tool checks scope as the first thing it does. Missing scope is HTTP 403 with `Missing scope: ` — the tool body never runs.
## Scope matrix
| Tool | Scope | Notes |
| --- | --- | --- |
| `check_domain_availability` | `availability:read` | |
| `get_tld_info` | `availability:read` | |
| `whoami` | `orgs:read` | |
| `list_my_orgs` | `orgs:read` | |
| `get_org` | `orgs:read` | |
| `list_org_members` | `orgs:read` | |
| `list_org_domains` | `domains:read` | |
| `get_domain` | `domains:read` | `auth_code` redacted unless caller also has `domains:write` |
| `update_domain_settings` | `domains:write` | |
| `register_domains` | `domains:write` | Spends money |
| `renew_domain` | `domains:write` | Spends money |
| `list_dns_records` | `dns:read` | |
| `create_dns_record`, `update_dns_record`, `delete_dns_record` | `dns:write` | |
| `list_dns_presets`, `get_active_dns_presets` | `dns:read` | |
| `apply_dns_preset`, `remove_dns_preset` | `dns:write` | Always confirms |
| `list_contacts`, `get_domain_contacts` | `contacts:read` | |
| `create_contact`, `update_contact`, `delete_contact` | `contacts:write` | Owner/admin only |
| `set_domain_contact`, `unset_domain_contact` | `contacts:write` | Owner/admin only |
| `get_balance` | `orgs:read` | |
| `list_my_confirmations` | `orgs:read` | |
## Defaults
OAuth sessions are minted with: `availability:read`, `orgs:read`, `orgs:write`, `domains:read`, `domains:write`, `dns:read`, `dns:write`, `contacts:read`, `contacts:write`. That's enough to do everything except billing.
API keys ship with whatever you tick at mint time. Use the tightest scope set that gets the job done.
## Org role gates
A few tools also check the caller's role within the org, on top of scope:
- Contact write tools (create, update, delete, set, unset) require `owner` or `admin`.
- Org settings, member management require `owner` or `admin`.
A `member` with `contacts:write` will still be rejected with "Admin or owner role required for this organization".
---
# Claude Desktop
Connect DomainGenius MCP to Anthropic's Claude Desktop app.
URL: /mcp/install/claude-desktop
The endpoint is `https://mcp.domaingenius.com.au/mcp`.
## Native connector (recommended)
Click the **+** in the chat composer, or open the **Connectors** panel from the settings menu.
Pick **Add custom connector**, paste `https://mcp.domaingenius.com.au/mcp`, and confirm.
Claude Desktop opens a browser tab to the DomainGenius OAuth screen. Sign in with your Clerk account, pick the org, and approve the requested scopes.
Type "what orgs do I belong to?" — Claude should call `whoami` and list your orgs.
## Manual config (API key)
If you'd rather use a long-lived API key instead of OAuth, edit Claude Desktop's config:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Mint the key at [`/dashboard/api-keys`](https://app.domaingenius.com.au/dashboard/api-keys). Restart Claude Desktop after saving.
---
# Claude Code
Connect DomainGenius MCP to Claude Code (CLI).
URL: /mcp/install/claude-code
The endpoint is `https://mcp.domaingenius.com.au/mcp`.
## OAuth (recommended)
```bash
claude mcp add --transport http domaingenius https://mcp.domaingenius.com.au/mcp
```
The first call opens a browser tab for the OAuth handshake. Pick your org, approve the scopes.
## API key
```bash
claude mcp add --transport http domaingenius https://mcp.domaingenius.com.au/mcp \
--header "Authorization=Bearer dg_live_..."
```
## Verify
```bash
claude mcp list
```
Then in a chat: "list my DomainGenius orgs" — Claude Code should call `whoami`.
---
# Cursor
Connect DomainGenius MCP to Cursor.
URL: /mcp/install/cursor
The endpoint is `https://mcp.domaingenius.com.au/mcp`. Edit `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp"
}
}
}
```
Cursor will open the OAuth flow in your browser the first time the server is contacted.
```json
{
"mcpServers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Restart Cursor. Open the **MCP** panel in settings — the `domaingenius` server should show green with the tool count.
---
# Windsurf
Connect DomainGenius MCP to Windsurf (Codeium).
URL: /mcp/install/windsurf
The endpoint is `https://mcp.domaingenius.com.au/mcp`. Edit `~/.codeium/windsurf/mcp_config.json`:
```json
{
"mcpServers": {
"domaingenius": {
"serverUrl": "https://mcp.domaingenius.com.au/mcp"
}
}
}
```
```json
{
"mcpServers": {
"domaingenius": {
"serverUrl": "https://mcp.domaingenius.com.au/mcp",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Restart Windsurf. Open Cascade and check **Available tools** — DomainGenius should appear.
---
# VS Code
Connect DomainGenius MCP to VS Code's MCP support.
URL: /mcp/install/vscode
The endpoint is `https://mcp.domaingenius.com.au/mcp`. Project-scoped config goes in `.vscode/mcp.json`; user-scoped goes in your VS Code settings under `mcp.servers`.
```json
{
"servers": {
"domaingenius": {
"type": "http",
"url": "https://mcp.domaingenius.com.au/mcp"
}
}
}
```
```json
{
"servers": {
"domaingenius": {
"type": "http",
"url": "https://mcp.domaingenius.com.au/mcp",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Reload the window (`Developer: Reload Window`). The MCP panel lists `domaingenius` with its tool count once the server connects.
---
# Zed
Connect DomainGenius MCP as a Zed context server.
URL: /mcp/install/zed
The endpoint is `https://mcp.domaingenius.com.au/mcp`. Open Zed settings (`cmd+,`) and add:
```json
{
"context_servers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp"
}
}
}
```
```json
{
"context_servers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Reload settings. Open the assistant panel and confirm `domaingenius` appears under context servers.
---
# Cline
Connect DomainGenius MCP to the Cline VS Code extension.
URL: /mcp/install/cline
The endpoint is `https://mcp.domaingenius.com.au/mcp`.
Click the Cline icon in the activity bar, then the **MCP Servers** tab.
Pick **Edit MCP Settings**. The settings file opens in the editor.
```json
{
"mcpServers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp",
"transportType": "http"
}
}
}
```
```json
{
"mcpServers": {
"domaingenius": {
"url": "https://mcp.domaingenius.com.au/mcp",
"transportType": "http",
"headers": {
"Authorization": "Bearer dg_live_..."
}
}
}
}
```
Save. The Cline panel reloads the server list. Ask Cline to "list my DomainGenius orgs".
---
# Availability tools
Check whether domains can be registered, and look up TLD pricing and eligibility.
URL: /mcp/tools/availability
## `check_domain_availability`
Check up to 30 domains in one call. Cached 1 day for available, 30 days for unavailable.
Required scope: `availability:read`.
List of domain names. Lowercase preferred. Maximum 30 per call.
The input domain.
Whether the domain can be registered. `null` if registry returned an error.
`"cache"`, `"synergy"`, or `"unknown"`.
Whether DomainGenius supports this TLD.
Year-1 registration cost in AUD (only when `available=true`).
```json Example invocation
{
"tool": "check_domain_availability",
"arguments": {
"domains": ["example.com.au", "openai.com"]
}
}
```
```json Example response
[
{
"domain": "example.com.au",
"available": true,
"source": "synergy",
"tld_enabled": true,
"register_price_aud": 24.95,
"register_price_display": "$24.95 AUD/year"
},
{
"domain": "openai.com",
"available": false,
"source": "cache",
"tld_enabled": true
}
]
```
## `get_tld_info`
Pricing, period limits, and registry eligibility for a single TLD.
Required scope: `availability:read`.
TLD without leading dot. e.g. `com.au`, `net`, `org`.
Whether DomainGenius supports registration of this TLD.
Minimum registration period.
Maximum registration period.
Map keyed by `{n}_year` for each supported period.
Renewal cost per year in AUD.
Transfer-in cost in AUD.
Whether WHOIS privacy can be enabled on this TLD.
Plain-language registry eligibility (e.g. ABN required for `.com.au`).
---
# Contact tools
Manage org-wide contacts and assign them to domains as registrant, admin, technical, or billing.
URL: /mcp/tools/contacts
A contact is a reusable address record. Each domain has up to four roles: `registrant`, `admin`, `technical`, `billing`. The same contact can fill more than one role.
## `list_contacts`
Required scope: `contacts:read`.
Organisation OID from `whoami`.
Returns the org's contacts.
## `create_contact`
Required scope: `contacts:write`. Caller must be `owner` or `admin`.
ISO-2 country code (e.g. `AU`).
International format (e.g. `+61.412345678`).
Optional company name.
Optional second address line.
## `update_contact`
Replaces an entire contact record — supply every field, not just changed ones.
Required scope: `contacts:write`. Caller must be `owner` or `admin`.
Contact UUID.
All other params match `create_contact`.
## `delete_contact`
Required scope: `contacts:write`. Caller must be `owner` or `admin`.
Returns `{ "deleted": true, "contact_id": "..." }`.
## `get_domain_contacts`
Required scope: `contacts:read`.
Returns up to four entries — one per assigned role. Missing roles aren't in the list.
## `set_domain_contact`
Required scope: `contacts:write`. Caller must be `owner` or `admin`.
One of `registrant`, `admin`, `technical`, `billing`.
UUID from `list_contacts`.
The change is local. The next sync cycle pushes it to the registrar.
## `unset_domain_contact`
Required scope: `contacts:write`. Caller must be `owner` or `admin`.
---
# DNS tools
Read and write DNS records, plus apply preset templates for common providers.
URL: /mcp/tools/dns
DNS lives on Cloudflare. The domain must have `dns_management = "domaingenius"` and a configured `cloudflare_zone_id`. Use `update_domain_settings` to enable managed DNS first.
Write operations route through the agent confirmation pipeline. If the user's threshold is exceeded, the response is `status: "pending_confirmation"` with a token + URL — surface the URL to the user, they approve, then re-call with `request_id`.
## `list_dns_records`
Required scope: `dns:read`.
A, AAAA, CNAME, MX, TXT, NS, etc.
Seconds, or `1` for auto.
## `create_dns_record`
Required scope: `dns:write`.
Record type.
Apex (`example.com.au`) or subdomain.
IP, target hostname, TXT body, etc.
TTL in seconds, or `1` for auto.
Required for MX and SRV.
Whether Cloudflare should proxy.
Idempotency key. Auto-generated if omitted.
## `update_dns_record`
Replaces a record — supply every field. Same scope and params as `create_dns_record` plus:
Record id from `list_dns_records`.
## `delete_dns_record`
Required scope: `dns:write`.
## `list_dns_presets`
Catalog of preset templates (Vercel, Cloudflare Pages, Google Workspace MX, etc.).
Required scope: `dns:read`.
## `get_active_dns_presets`
Detect which presets are currently applied to the domain's zone.
Required scope: `dns:read`.
Returns `{ "active": ["vercel", "google_mx"] }`.
## `apply_dns_preset`
Deletes records the preset conflicts with, then creates the preset's records. Always confirms — `bulk_count=5` forces it through the confirmation pipeline.
Required scope: `dns:write`.
Key from `list_dns_presets`.
Per-preset inputs (e.g. Vercel team id).
Returns `{ "created": int, "deleted": int }`.
## `remove_dns_preset`
Removes records belonging to the preset. Same confirmation behaviour as apply.
Required scope: `dns:write`.
---
# Domain tools
List, inspect, and update settings on domains the org owns.
URL: /mcp/tools/domains
Read-only tools require `domains:read`. `update_domain_settings` requires `domains:write`. The EPP `auth_code` only ships in responses to keys with `domains:write`.
## `list_org_domains`
Cursor-paginated listing of an org's domains.
Required scope: `domains:read`.
Filter by state: `registered`, `expired`, `redemption`, `external`, `deleted`, `failed`, `pending`.
Domain name from a previous page's `next_cursor`.
Max 100.
Domain summaries (see `get_domain` for shape).
Total matching, ignoring cursor.
## `get_domain`
Full record for one domain, including subscription and (for `domains:write` keys) the EPP `auth_code`.
Required scope: `domains:read`.
`registered`, `expired`, `redemption`, etc.
`domaingenius` or `external`.
ISO 8601 timestamp.
EPP transfer code. Returned only with `domains:write` scope.
Period, price, auto-renew status.
## `update_domain_settings`
Update the safe per-domain knobs.
Required scope: `domains:write`.
Toggle WHOIS privacy. Some TLDs (e.g. `.com.au`) ignore privacy at the registry.
List or unlist on the marketplace.
Minimum offer in cents.
Absolute http(s) URL. Empty string clears the redirect.
DNS, nameserver, and contact-role changes are out of scope here — see the DNS, contact, and (API-only) registrar-sync tools.
---
# Organisation tools
Discover the caller's identity and orgs, then read org details and members.
URL: /mcp/tools/orgs
Call `whoami` first to discover the `org_oid` values you'll pass to every other tool.
## `whoami`
The authenticated user plus a flat list of orgs.
Required scope: `orgs:read`.
Platform-level superuser flag.
Per-org: `oid`, `name`, `slug`, `role`, `balance_aud`, `balance_display`.
## `list_my_orgs`
Same as `whoami.orgs` but with extra fields.
Required scope: `orgs:read`.
## `get_org`
Required scope: `orgs:read`.
`owner`, `admin`, or `member`.
## `list_org_members`
Required scope: `orgs:read`.
Returns email, display name, role, and join date for each member. Clerk IDs are deliberately omitted.
---
# Registration tools
Register and renew domains, read the org balance, and poll pending confirmations.
URL: /mcp/tools/registration
These tools spend money. Every state-changing call routes through the agent confirmation pipeline — when the action exceeds the user's threshold or registers ≥5 domains in one call, the response is `status: "pending_confirmation"` with a token and `approve_url`.
The user must approve out-of-band. Call again with the same `request_id` after approval to execute.
## `register_domains`
Register one or more domains for the org.
Required scope: `domains:write`.
List of domain names.
1–10.
Client idempotency key. Same id replays the original ActionLog row instead of registering twice.
Free-text rationale; logged as a hash for audit.
`balance` debits the prepaid org balance (auto-tops-up if configured); `card` charges the saved default card directly.
`completed`, `pending_confirmation`, `duplicate`, `failed`, `requires_action` (3DS).
Present when `pending_confirmation`: `oid`, `token`, `expires_at`, `amount_cents`, `approve_url`.
Per-domain outcome on success.
Present on `failed`.
## `renew_domain`
Renew one domain.
Required scope: `domains:write`.
1–10.
Same response shape as `register_domains`. Only `balance` funding is supported.
## `get_balance`
Required scope: `orgs:read`.
## `list_my_confirmations`
The caller's pending confirmations. Use after a `pending_confirmation` response to poll for status, or to surface a list of "things waiting on you" to the user.
Required scope: `orgs:read`.
---
# CONTRIBUTING
URL: /CONTRIBUTING
# Contributing to DomainGenius docs
Tangly site. Bun-only.
## Local dev
```bash
bun x tangly dev --host # via taskmux: taskmux start docs
```
Dev server: or `http://docs.` if taskmux is routing.
## Refresh OpenAPI
The `openapi.json` is checked in. Regenerate when API routes change:
```bash
taskmux start api
bun docs/scripts/fetch-openapi.ts
```
The script strips `admin_*` paths and orphaned schemas.
## Validate
```bash
bun x tangly check --strict
```
## Build + preview
```bash
bun x tangly build
bun x tangly preview
```
## Deploy
Cloudflare Workers (static assets):
```bash
bun x tangly build
bunx wrangler deploy
```
Custom domain: `docs.domaingenius.com.au` (configured in `wrangler.toml`).
---
# List Market Domains
List all active for-sale domains with optional filters.
This is a public endpoint for the DomainGenius marketplace.
URL: /reference/list-market-domains-api-v1-market-get
---
# Get Market Domain
Get single for-sale domain with full stats.
URL: /reference/get-market-domain-api-v1-market-domain-get
---
# Check Availability
Check if a single domain is available for registration.
Args:
domain: Domain name to check (e.g., example.com)
Returns:
Availability status with timestamp
URL: /reference/check-availability-api-v1-domains-availability-get
---
# Check Bulk Availability
Check availability for multiple domains (max 30).
Args:
request: List of domains to check
Returns:
Availability results for all domains
URL: /reference/check-bulk-availability-api-v1-domains-availability-bulk-post
---
# Search Stream
Stream domain availability results via SSE.
URL: /reference/search-stream-api-v1-domains-search-stream-get
---
# Get For Sale
Get for-sale listing for a domain.
URL: /reference/get-for-sale-api-v1-domains-domain-for-sale-get
---
# Create Or Update For Sale
Create or update for-sale listing for a domain.
URL: /reference/create-or-update-for-sale-api-v1-domains-domain-for-sale-put
---
# Delete For Sale
Delete for-sale listing for a domain.
URL: /reference/delete-for-sale-api-v1-domains-domain-for-sale-delete
---
# Get Parked
Get parked config for a domain. Auto-creates with defaults if missing.
URL: /reference/get-parked-api-v1-domains-domain-parked-get
---
# Update Parked
Update parked config for a domain.
URL: /reference/update-parked-api-v1-domains-domain-parked-put
---
# Estimatevaluation
Estimate the market value of a domain name.
URL: /reference/estimate-valuation-api-v1-valuation-estimate-post
---
# Getvaluation
Get a persisted valuation by ID.
URL: /reference/get-valuation-api-v1-valuation-valuation-id-get
---
# Getvaluationbydomain
Get the latest valuation for a domain.
URL: /reference/get-valuation-by-domain-api-v1-valuation-domain-domain-get
---
# Submitfeedback
Submit thumbs up/down feedback for a valuation.
URL: /reference/submit-feedback-api-v1-valuation-valuation-id-feedback-patch
---
# Getvaluationhistory
Get paginated valuation history (admin).
URL: /reference/get-valuation-history-api-v1-valuation-history-list-get
---
# Getme
Return authenticated user profile. Accepts Clerk JWT or dg_xxx API key.
URL: /reference/get-me-api-v1-me-get
---
# Updateme
Update first/last name.
URL: /reference/update-me-api-v1-me-patch
---
# Listmyorgs
List orgs the user belongs to with role and domain count.
Accepts Clerk JWT or dg_xxx API key. API keys must include `orgs:read`.
URL: /reference/list-my-orgs-api-v1-me-orgs-get
---
# Listapikeys
List all API keys for the authenticated user.
URL: /reference/list-api-keys-api-v1-me-api-keys-get
---
# Createapikey
Create a new API key. The full key is returned once — store it immediately.
URL: /reference/create-api-key-api-v1-me-api-keys-post
---
# Revokeapikey
Revoke an API key. Immediately invalidates all requests using this key.
URL: /reference/revoke-api-key-api-v1-me-api-keys-key-id-delete
---
# Checkslug
Check if an org slug is available.
URL: /reference/check-slug-api-v1-orgs-check-slug-get
---
# Createorg
Create org. Creator becomes owner. Max 5 owned orgs per user.
URL: /reference/create-org-api-v1-orgs-post
---
# Getorg
Org detail with counts.
URL: /reference/get-org-api-v1-orgs-org-oid-get
---
# Updateorg
Update org name, slug or billing_email.
URL: /reference/update-org-api-v1-orgs-org-oid-patch
---
# Deleteorg
Soft delete org.
URL: /reference/delete-org-api-v1-orgs-org-oid-delete
---
# Listmembers
List org members.
URL: /reference/list-members-api-v1-orgs-org-oid-members-get
---
# Addmember
Add member by email. User must already exist.
URL: /reference/add-member-api-v1-orgs-org-oid-members-post
---
# Updatememberrole
Update member role. Cannot change own role or demote last owner.
URL: /reference/update-member-role-api-v1-orgs-org-oid-members-user-oid-patch
---
# Removemember
Remove member. Cannot remove last owner.
URL: /reference/remove-member-api-v1-orgs-org-oid-members-user-oid-delete
---
# Listdomains
List domains with pagination, search, filters, and sort.
URL: /reference/list-domains-api-v1-orgs-org-oid-domains-get
---
# Getdomain
Full domain detail.
URL: /reference/get-domain-api-v1-orgs-org-oid-domains-domain-get
---
# Updatedomain
Update domain configuration.
URL: /reference/update-domain-api-v1-orgs-org-oid-domains-domain-patch
---
# Getdomainstatus
Domain status summary.
URL: /reference/get-domain-status-api-v1-orgs-org-oid-domains-domain-status-get
---
# Renewdomain
Manually renew a domain. Routes through requestAction so threshold,
balance + auto top-up, idempotency, and audit log all apply.
URL: /reference/renew-domain-api-v1-orgs-org-oid-domains-domain-renew-post
---
# Syncdomainfromregistrar
Refresh this domain's state from the registrar (Synergy).
URL: /reference/sync-domain-from-registrar-api-v1-orgs-org-oid-domains-domain-sync-post
---
# Getdomainhealth
Get latest health check for a domain.
URL: /reference/get-domain-health-api-v1-orgs-org-oid-domains-domain-health-get
---
# Triggerhealthcheck
Trigger a fresh health check for a domain.
URL: /reference/trigger-health-check-api-v1-orgs-org-oid-domains-domain-health-check-post
---
# Enabledns
Enable DomainGenius-managed DNS (sets up Cloudflare zone + records + worker).
URL: /reference/enable-dns-api-v1-orgs-org-oid-domains-domain-dns-enable-post
---
# Disabledns
Switch to external DNS management (keeps Cloudflare zone for re-enable).
URL: /reference/disable-dns-api-v1-orgs-org-oid-domains-domain-dns-disable-post
---
# Checktransfer
Check if a domain can be transferred in.
URL: /reference/check-transfer-api-v1-orgs-org-oid-domains-transfer-check-post
---
# Transferdomain
Initiate domain transfer into this org.
All transfers are treated as external regardless of whether the domain
exists elsewhere in the system — the recipient never sees source account info.
The domain record is only created/updated when the transfer completes.
URL: /reference/transfer-domain-api-v1-orgs-org-oid-domains-transfer-post
---
# Listtransfers
List pending and recent domain transfers for this org.
URL: /reference/list-transfers-api-v1-orgs-org-oid-domains-transfers-get
---
# Listdnsrecords
List DNS records from Cloudflare.
URL: /reference/list-dns-records-api-v1-orgs-org-oid-domains-domain-dns-get
---
# Creatednsrecord
URL: /reference/create-dns-record-api-v1-orgs-org-oid-domains-domain-dns-post
---
# Updatednsrecord
URL: /reference/update-dns-record-api-v1-orgs-org-oid-domains-domain-dns-record-id-put
---
# Deletednsrecord
URL: /reference/delete-dns-record-api-v1-orgs-org-oid-domains-domain-dns-record-id-delete
---
# Listpresetsendpoint
URL: /reference/list-presets-endpoint-api-v1-orgs-org-oid-domains-domain-dns-presets-get
---
# Applydnspreset
URL: /reference/apply-dns-preset-api-v1-orgs-org-oid-domains-domain-dns-presets-apply-post
---
# Getactivepresetsendpoint
URL: /reference/get-active-presets-endpoint-api-v1-orgs-org-oid-domains-domain-dns-presets-active-get
---
# Removednspresetendpoint
URL: /reference/remove-dns-preset-endpoint-api-v1-orgs-org-oid-domains-domain-dns-presets-remove-post
---
# Listforwarding
URL: /reference/list-forwarding-api-v1-orgs-org-oid-domains-domain-forwarding-get
---
# Createforwarding
URL: /reference/create-forwarding-api-v1-orgs-org-oid-domains-domain-forwarding-post
---
# Updateforwarding
URL: /reference/update-forwarding-api-v1-orgs-org-oid-domains-domain-forwarding-forwarding-id-patch
---
# Deleteforwarding
URL: /reference/delete-forwarding-api-v1-orgs-org-oid-domains-domain-forwarding-forwarding-id-delete
---
# Setwwwtoapex
URL: /reference/set-www-to-apex-api-v1-orgs-org-oid-domains-domain-forwarding-www-to-apex-post
---
# Getwwwtoapex
URL: /reference/get-www-to-apex-api-v1-orgs-org-oid-domains-domain-forwarding-www-to-apex-get
---
# Listcontactsendpoint
List contacts belonging to this org.
URL: /reference/list-contacts-endpoint-api-v1-orgs-org-oid-contacts-get
---
# Createcontactendpoint
Create a contact for this org.
URL: /reference/create-contact-endpoint-api-v1-orgs-org-oid-contacts-post
---
# Updatecontactendpoint
Update an existing contact.
URL: /reference/update-contact-endpoint-api-v1-orgs-org-oid-contacts-contact-id-put
---
# Deletecontactendpoint
Delete a contact.
URL: /reference/delete-contact-endpoint-api-v1-orgs-org-oid-contacts-contact-id-delete
---
# Listaueligibility
List AU eligibility records for this org.
URL: /reference/list-au-eligibility-api-v1-orgs-org-oid-contacts-eligibility-get
---
# Createaueligibility
Create an AU eligibility record for this org.
URL: /reference/create-au-eligibility-api-v1-orgs-org-oid-contacts-eligibility-post
---
# Updateaueligibility
Update an AU eligibility record.
URL: /reference/update-au-eligibility-api-v1-orgs-org-oid-contacts-eligibility-eligibility-id-put
---
# Deleteaueligibility
Delete an AU eligibility record.
URL: /reference/delete-au-eligibility-api-v1-orgs-org-oid-contacts-eligibility-eligibility-id-delete
---
# Listuseligibility
List US eligibility records for this org.
URL: /reference/list-us-eligibility-api-v1-orgs-org-oid-contacts-eligibility-us-get
---
# Createuseligibility
Create a US eligibility record for this org.
URL: /reference/create-us-eligibility-api-v1-orgs-org-oid-contacts-eligibility-us-post
---
# Updateuseligibility
Update a US eligibility record.
URL: /reference/update-us-eligibility-api-v1-orgs-org-oid-contacts-eligibility-us-eligibility-id-put
---
# Deleteuseligibility
Delete a US eligibility record.
URL: /reference/delete-us-eligibility-api-v1-orgs-org-oid-contacts-eligibility-us-eligibility-id-delete
---
# Listdomaincontacts
Get contact assignments for a domain. Auto-syncs from registrar if stale.
URL: /reference/list-domain-contacts-api-v1-orgs-org-oid-domains-domain-contacts-get
---
# Assigncontact
Assign an org contact to a domain for a given type. Also pushes to Synergy.
URL: /reference/assign-contact-api-v1-orgs-org-oid-domains-domain-contacts-contact-type-put
---
# Removecontactassignment
Remove a contact assignment for a domain type.
URL: /reference/remove-contact-assignment-api-v1-orgs-org-oid-domains-domain-contacts-contact-type-delete
---
# Copyregistranttoall
Copy registrant contact to admin, technical, and billing. Pushes to Synergy.
URL: /reference/copy-registrant-to-all-api-v1-orgs-org-oid-domains-domain-contacts-copy-registrant-post
---
# Syncfromregistrar
Pull contacts from Synergy and update DB.
URL: /reference/sync-from-registrar-api-v1-orgs-org-oid-domains-domain-contacts-sync-post
---
# Getauditlog
Paginated audit log for the org. Filterable by domain, action, actor.
URL: /reference/get-audit-log-api-v1-orgs-org-oid-audit-log-get
---
# Getbilling
Get billing overview — balance, auto-topup settings, payment methods.
URL: /reference/get-billing-api-v1-orgs-org-oid-billing-get
---
# Createdeposit
Top up balance.
If the org has a saved default card → charge it inline and return
`{ ok, balance_cents }`. If 3DS is required → return
`{ requires_action, client_secret, payment_intent_id }`. Otherwise →
fall back to Stripe Checkout and return `{ checkout_url }`.
URL: /reference/create-deposit-api-v1-orgs-org-oid-billing-deposit-post
---
# Updateautotopup
Update auto top-up settings. Captures PSD2 consent on enable.
Agent-initiated callers (X-Initiator: agent) are rejected on this route —
payment-method changes always require a human in the dash.
URL: /reference/update-auto-topup-api-v1-orgs-org-oid-billing-auto-topup-patch
---
# Detachpaymentmethod
Detach a saved payment method. Clears default if it was the default.
Agent-initiated callers are rejected — payment-method delete is dashboard-only.
URL: /reference/detach-payment-method-api-v1-orgs-org-oid-billing-payment-methods-payment-method-id-delete
---
# Listtransactions
Paginated transaction history.
URL: /reference/list-transactions-api-v1-orgs-org-oid-billing-transactions-get
---
# Listpaymentmethods
List saved payment methods.
URL: /reference/list-payment-methods-api-v1-orgs-org-oid-billing-payment-methods-get
---
# Createsetupintentendpoint
Create a Stripe SetupIntent for adding a payment method.
URL: /reference/create-setup-intent-endpoint-api-v1-orgs-org-oid-billing-setup-intent-post
---
# Createsavecardcheckout
Create a Stripe-hosted Checkout in setup mode to save a card.
URL: /reference/create-save-card-checkout-api-v1-orgs-org-oid-billing-save-card-checkout-post
---
# Createportalsession
Create a Stripe billing portal session.
URL: /reference/create-portal-session-api-v1-orgs-org-oid-billing-portal-post
---
# Processcheckoutendpoint
Process cart checkout — debit balance, charge Stripe if needed, enqueue registrations.
URL: /reference/process-checkout-endpoint-api-v1-orgs-org-oid-billing-checkout-post
---
# Getconfirmation
URL: /reference/get-confirmation-api-v1-confirmations-token-get
---
# Approveconfirmationroute
Approve a pending confirmation and execute the queued action.
URL: /reference/approve-confirmation-route-api-v1-confirmations-token-approve-post
---
# Denyconfirmationroute
URL: /reference/deny-confirmation-route-api-v1-confirmations-token-deny-post
---
# Listmyconfirmations
URL: /reference/list-my-confirmations-api-v1-me-confirmations-get
---
# Listpricing
List all enabled TLDs with RRP prices.
URL: /reference/list-pricing-api-v1-pricing-get
---
# Gettldpricing
Get full RRP pricing for a single TLD.
URL: /reference/get-tld-pricing-api-v1-pricing-tld-get
---
# List Redirects
List all redirects for a domain.
URL: /reference/list-redirects-api-v1-domains-domain-redirects-get
---
# Create Redirect
Create a new redirect for a domain.
URL: /reference/create-redirect-api-v1-domains-domain-redirects-post
---
# Update Redirect
Update an existing redirect.
URL: /reference/update-redirect-api-v1-domains-domain-redirects-redirect-id-put
---
# Delete Redirect
Delete a redirect.
URL: /reference/delete-redirect-api-v1-domains-domain-redirects-redirect-id-delete
---
# Update Redirect Priorities
Update redirect priorities (for drag-drop reordering).
URL: /reference/update-redirect-priorities-api-v1-domains-domain-redirects-priorities-patch
---
# Gettraffic
Get traffic estimation for domain + competitors.
URL: /reference/get-traffic-api-v1-tools-traffic-get
---
# Gettechnology
Get technology stack for domain.
URL: /reference/get-technology-api-v1-tools-technology-get
---
# Getblacklistcheck
Check domain against Spamhaus, SURBL, URIBL, Barracuda, SpamCop blacklists.
URL: /reference/get-blacklist-check-api-v1-tools-blacklist-get
---
# Getkeyworddifficultyendpoint
Get keyword difficulty scores for up to 5 keywords.
URL: /reference/get-keyword-difficulty-endpoint-api-v1-tools-keyword-difficulty-post
---
# Health Check
Health check endpoint.
URL: /reference/health-check-health-get
---
# Root
Root endpoint.
URL: /reference/root-get