Client API Reference
Authentication
There are two ways to authenticate. Which one you use depends on what you're building.
| Method | Use it for | How |
|---|---|---|
| Session login | Signing a human into this portal | Two-step email/password login, returns a bearer token |
| API key | Scripts, integrations, anything unattended | A long-lived key you generate yourself, below |
You don't need both. A couple of endpoints — managing sub-accounts, managing your own API keys — are portal-login only; noted where relevant.
Getting an API key
- Log in to this portal, then go to Account.
- Create a new key, giving it a label and at least one allowed IP address or CIDR range (e.g.
203.0.113.4or203.0.113.0/24). - Copy the key immediately — it's shown exactly once and cannot be retrieved again. If you lose it, revoke it and create a new one.
- Requests from any IP not in that key's allowlist are rejected, even with a valid key. There is no "allow from anywhere" option — this is by design.
Send it as a bearer token on every request:
Session login
Login is two steps, because the email on an account can be shared across more than one of your organization's client records — for example, if you manage several accounts from one inbox. Step 1 tells you which account(s) that email belongs to; step 2 verifies the password for the one you pick.
Exactly one account? Skip straight to step 2. More than one? Show a picker using client_display_name before asking for a password.
Use token as a bearer token on every subsequent request. Watch for 401 UNAUTHORIZED as the signal to log in again.
/v1/auth/lookup and /v1/auth/login are rate-limited per source IP (10 attempts / 5 minutes) as a brute-force guard. Expect 429 RATE_LIMITED if you exceed that — back off rather than retry immediately.Response format
Every response uses the same envelope:
On failure:
request_id is worth logging on your end — quote it if you ever report an issue, it lets us trace the exact request server-side.
Common error codes
| Status | error.code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | A required field was missing or invalid |
| 401 | UNAUTHORIZED | Missing, invalid, or expired credentials |
| 401 | INVALID_CREDENTIALS | Wrong password on login |
| 403 | FORBIDDEN | Authenticated, but not allowed to do this |
| 404 | NOT_FOUND | Doesn't exist, or doesn't belong to your account |
| 409 | CONFLICT | Doesn't make sense in the resource's current state |
| 429 | RATE_LIMITED | Too many requests — back off and retry later |
| 500 / 502 | INTERNAL_ERROR, etc. | Something went wrong on our end — safe to retry |
Data isolation
Every endpoint below only ever returns or affects data belonging to your own
account. Passing another account's ID anywhere returns 404 NOT_FOUND,
the same as if it didn't exist. This is enforced on every request server-side, not just hidden
in the portal UI.
Domains
Lists every domain on your account.
A single domain, including its owner/admin/tech contacts.
Pricing
Resolves the price for a given TLD + action (+ period, for period-based actions like registration/renewal/transfer). Reflects any account-specific pricing you have — this is the price you'd actually be charged.
Returns 404 PRICE_NOT_FOUND if that TLD/action combination isn't orderable for your account.
Domain actions
The way you request anything to actually happen to a domain — a renewal, a DNS change, an ownership transfer, and so on.
Registering a brand-new domain? Omit domain_id and pass tld and domain_name instead — the domain is created as part of the request.
What happens next
- Free (
price_amount: "0.00") — dispatched immediately;statusissent_to_supplier(orpendingwith awarningif dispatch needs a retry on our end — not something you need to act on). - Paid — queued onto an open order; the response includes
order_id. The action stayspendinguntil the resulting invoice is paid, then dispatches automatically.
Lists actions requested on a specific domain. domain_id is required — this endpoint always scopes to one domain.
Idempotency-Key header on POST /v1/domain-actions if you might retry the same request (e.g. after a timeout) — a retried request with the same key won't create a duplicate action.Invoices
List / fetch a single invoice, including its line items.
Decode content_base64 to get the raw PDF file bytes.
Sub-accounts portal login only
Lets an account owner create and manage additional logins under the same account — separate
billing/tech contacts, each with their own credentials. Requires a portal session with
the owner role; not available via API key.
API keys portal login only
Self-service management of your own API keys, including the one you're currently using — also portal-login only, so a compromised key can never mint another key or widen its own access.
Returns the raw key once, in the response — save it now.
Rate limits
| Bucket | Limit |
|---|---|
Login attempts (/v1/auth/lookup, /v1/auth/login) | 10 / 5 min, per source IP |
| API key usage | 120 / min, per key |
Exceeding either returns 429 RATE_LIMITED. Build in a backoff/retry — repeatedly retrying immediately will just keep tripping the limit.
Health check
Returns {"status":"ok"} — useful for your own monitoring, doesn't touch anything else.
Questions, or something not behaving as documented? Include the request_id from the response when you reach out.