API v1 · REST · JSON

Developer API

Check and buy domains, list them for sale and track your sales from your own code — with the same engine and prices as the website.

Base URL
URL
https://hqclouds.com/api/v1

What the API can do

Domain checks

Whether a domain is available, registration and renewal prices.

Buying from balance

Registration with the same engine and prices as the website, with a spend limit per key.

My domains

Your domains, paid-until dates, nameservers and whether they can be listed for sale.

Sell domains

List domains, change price and description, remove them from sale.

Buy, then list

The order number from the purchase response lists the domain in the marketplace right away, and AI writes the card in Russian and English.

Sales history

Sales, marketplace commission and how much was credited to your balance.

Marketplace search

Public listing search with filters — no token needed.

The API is server-side: your script, bot or service (for example, HQName) calls HQClouds over HTTPS with a token from the dashboard. All amounts are in USD; money is charged to your HQClouds balance.

Quick start

  1. Sign in or sign up to HQClouds. If you plan to buy domains, top up your balance and fill in the domain owner contacts (WHOIS) once: WHOIS contacts.
  2. In the dashboard, open the “API” section and create a key: name, scopes and daily spend limit.
  3. Copy the token — it is shown only once. Keep it in an environment variable or a secrets manager.
  4. Make your first request:
bash
export HQC_TOKEN="hqc_xxxxxxxx_..."

curl -s https://hqclouds.com/api/v1/me \
  -H "Authorization: Bearer $HQC_TOKEN"

Get an API token

Authentication

Every request (except the public marketplace search) sends the token in the Authorization header:

http
Authorization: Bearer hqc_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • The token is shown once at creation. We store only its hash — a token cannot be recovered, only reissued.
  • Do not put the token into website or mobile app code: the API is meant for server-side calls and CORS is closed for it.
  • If a token leaks, revoke the key in the dashboard: revocation is immediate.
  • The request body is JSON (Content-Type: application/json) or a regular form. For PATCH, forms must be application/x-www-form-urlencoded.
  • Error messages are in English; with an Accept-Language: ru header most of them come in Russian. The code field does not depend on the language — rely on it in your code.
  • The url links in responses point to site pages in the same language as the messages.
  • The listing card (headline, description, “good fit for” list) also follows the response language: with ?lang=ru or Accept-Language: ru it is in Russian, otherwise in English. This way you see exactly what a buyer sees in that language.

Key scopes

Scopes are set when the key is created. Give a key only what your software needs.

ScopeWhat it allows
readEvery key has it. Read access: account and balance, domains, orders, listings, sales, domain checks.
market:writeList, edit and delist domains in the marketplace, and request AI descriptions for them.
domains:registerBuy domains from the balance. Requires a daily spend limit.

Limits

60requests per minute per key. Over the limit — 429 with a Retry-After header; the remainder is in X-RateLimit-Remaining.
$100default daily spend limit — set your own when creating a key. Counted over the last 24 hours.
20domain purchases per hour per key — protection against a runaway script loop.
10valid keys per account: revoked and expired keys do not count.
  • Purchases run strictly one at a time: if another purchase is in progress you get 429 busy — retry in a few seconds with the same Idempotency-Key.
  • Premium domains are never sold via the API — only manually in the dashboard.
  • Public marketplace search: 60 requests per minute per IP.
  • AI listing descriptions: at most 2 generations at once per account, and the number of generations is limited too. Over the limit you get 429 ai_rate_limited with Retry-After; the listing stays for sale.

Key security

A token with the buy permission is access to your balance. Here is what protects it and how to keep it safe yourself.

Allowed IPs

  • When creating a key, list the addresses of the servers it works from: IPv4, IPv6 or subnets (for example, 203.0.113.0/24 or 2001:db8::/48), up to 20 entries.
  • A request from any other address gets 403 ip_not_allowed, even with a valid token: a leaked token cannot be used from someone else’s server. This is an extra layer, not a replacement for keeping the token secret — treat it like a password.
  • An IP allowlist does not work from Cloudflare Workers and similar platforms without a fixed address of their own: issue a separate key for them without a list, with minimal scopes and a daily limit.
  • Without a list, the key works from any address. The list cannot be edited: issue a new key and revoke the old one.

Brute-force protection

  • A failed sign-in is a request without a token, with an invalid, revoked or expired token, or from an address not on the allowlist.
  • More than 30 failed sign-ins per minute from one IP — 429 too_many_auth_failures until the end of the minute; more than 300 per hour — until the end of the hour.
  • For IPv6, both the address and its whole /64 network are counted — the network threshold is 10 times higher. If the network is blocked because of neighbours, a key whose IP allowlist includes your address keeps working.
  • We also detect large-scale guessing from many addresses at once and review it manually.
  • The response to an invalid token does not depend on whether such a key exists: neither the response nor its timing gives anything away.

Money and key issuance

  • The daily spend limit of a key with the domains:register scope can be at most $1000. It caps the damage even if the token leaks.
  • A key with the buy permission can only be issued after entering your account password.
  • Every new key triggers an email to the account address: name, scopes, limit, allowed IPs and the address it was issued from.
  • You can issue at most 10 keys per hour.
HTTPcodeMeaning
HTTP 401unauthorized, invalid_tokenThe token is missing, invalid, revoked or expired. Counts as a failed sign-in.
HTTP 403ip_not_allowedThe token is valid, but the key has an IP allowlist and the request came from another address. The address the server saw is in the message and in the ip field.
HTTP 403scope_requiredThe key lacks the required scope — issue a key that has it.
HTTP 429too_many_auth_failuresToo many failed sign-ins from your IP: more than 30 per minute or 300 per hour. Requests from this IP are blocked until the window ends; see Retry-After for the wait time.
HTTP 429rate_limitedThe per-key requests-per-minute limit was exceeded — wait Retry-After seconds.

How to keep keys safe

  • One key per integration: you can revoke it without breaking the others.
  • Only the scopes you need: listing lots does not need domains:register, and reading needs nothing but read.
  • Set allowed IPs for server-side scripts.
  • Rotate keys regularly: issue a new one (it can have an expiry), switch your program to it, revoke the old one.
  • Never put the token into website JavaScript, a mobile app or a repository — keep it in environment variables or a secrets manager.
  • Got an email about a key you did not issue? Revoke it right away and change your password.

Idempotent purchases

The connection can drop mid-purchase, and you will not know whether it went through. That is why every purchase requires an Idempotency-Key header: any unique string up to 100 characters (Latin letters, digits and - _ : .), such as a UUID.

  • Retrying with the same key is safe: the API returns the result of the first attempt and does not charge you twice.
  • A new key means a new purchase. Generate the key once per purchase and save it before sending the request.
  • Timeout, dropped connection or a 5xx response — retry with the same key. A 202 response means the order is with the registrar and the money is reserved: do not buy again, poll GET /domains/{domain}.
  • A retry response is marked idempotent_replay: true. After a 202, GET /domains/{domain} returns status: pending while the registrar is working and status: failed with refunded: true if registration failed.
  • The key is unique within the account: a repeat with another API key of the same account (for example, after a key rotation) returns the same purchase marked other_api_key: true. A key longer than 100 characters or with other characters is not trimmed but refused: 422 invalid_idempotency_key.
  • A repeat after a refusal before the registrar or after 404 not_started is a new attempt: the price and the spend limits are checked again. The Idempotency-Key is bound to the domain from the first attempt: the same key with another domain gives 422 idempotency_key_reused.
  • Lost the response and do not know the order number — GET /domains/register/{Idempotency-Key}: 200 — the order and its outcome, 202 — the purchase is still running, 404 not_started — it never reached the registrar and nothing was charged (repeat the POST with the same key). This request only reads: it buys and charges nothing.
http
-H "Idempotency-Key: 3f6d1c52-8a4e-4b0f-9e21-7c5d9a0b4e18"

Responses and errors

All responses are JSON in UTF-8. A successful response contains "ok": true. An error has "ok": false and an error object with a machine-readable code and a human-readable message. Amounts are strings with two decimals. Lists return items plus total, page, pages, per_page. The purchase amount in a response is exactly what was reserved or charged: if it is not a whole number of cents, the string carries all its digits.

json
{
  "ok": false,
  "error": {
    "code": "daily_limit",
    "message": "Daily spend limit reached: spent $95.00 of $100.00 in the last 24 hours, this purchase is $12.99."
  }
}
HTTPcodeMeaning
HTTP 200already_listedNot an error: the domain is already listed — a 200 response with the same listing and already_listed: true, nothing is changed.
HTTP 400invalid_jsonThe request body is not a JSON object.
HTTP 400bad_requestBad request: for example, a malformed parameter in the URL.
HTTP 401unauthorizedNo Authorization: Bearer header.
HTTP 401invalid_tokenThe token is wrong, revoked or expired.
HTTP 402insufficient_balanceNot enough money on the balance — top it up in the dashboard.
HTTP 403ip_not_allowedThe key has an IP allowlist and the request came from another address (the address is in the ip field).
HTTP 403scope_requiredThe key lacks the required scope.
HTTP 403no_spend_limitThe key has no daily spend limit — it cannot buy.
HTTP 404not_foundNo such API endpoint, domain or listing — or it is not yours.
HTTP 404order_not_foundNo such order — or it is not yours.
HTTP 404not_startedLookup by Idempotency-Key: the purchase with this key never reached the registrar and nothing was charged — repeat the POST with the same key.
HTTP 405method_not_allowedThis endpoint does not support this method.
HTTP 409registration_failedThe registrar refused after the reservation — the money is back on your balance (refunded: true).
HTTP 409not_availableThe domain is taken or its availability could not be confirmed — no money was charged. A retry with the same Idempotency-Key checks the domain again.
HTTP 409no_contactDomain owner contacts (WHOIS) are missing — fill them in once in your dashboard.
HTTP 409price_above_maxThe final price is above max_price — nothing was bought.
HTTP 409price_changedThe price rose between checking the request and reserving the money — nothing was bought or charged. The new price is in error.price, the checked one in error.confirmed_price.
HTTP 409premium_not_allowedPremium domain: manual purchase in the dashboard only.
HTTP 409…Other purchase refusals before the registrar — no money was charged, the reason is in message.
HTTP 409order_pendingThe registrar is still processing the order — the domain can be listed once it is registered. Retry after Retry-After seconds.
HTTP 409order_failedRegistration for the order failed and the money was returned — there is nothing to list.
HTTP 409domain_not_ownedThe domain from the order is no longer in your account: sold, transferred or deleted.
HTTP 409domain_not_realThe domain was bought in test mode (sandbox) and does not exist at the registrar — it cannot be listed for sale.
HTTP 409lot_not_activeThe listing is delisted or sold — it cannot be edited and no AI description can be requested for it.
HTTP 409lot_reservedA buyer is paying for the domain right now — until the reservation ends the listing cannot be edited, delisted or regenerated.
HTTP 409ai_in_progressThe AI description of this listing is already being generated by another request — check the listing after Retry-After seconds.
HTTP 413payload_too_largeThe request body is larger than 64 KB.
HTTP 422validation_failedInvalid data (price, category, the domain cannot be listed, etc.) — details in message.
HTTP 422domain_required, invalid_domain, invalid_field, idempotency_key_requiredA parameter is missing or has the wrong format.
HTTP 422invalid_idempotency_keyIdempotency-Key is longer than 100 characters or has invalid characters — the key is rejected, not truncated.
HTTP 422idempotency_key_reusedThis Idempotency-Key was already used to buy another domain.
HTTP 422invalid_max_pricemax_price is not a plain number (for example 1e3, true or text).
HTTP 422years_unsupportedOnly 1-year registrations are available via the API.
HTTP 422quote_failedCould not get the domain price — details in message.
HTTP 422invalid_statusUnknown status filter value for the listings or orders list.
HTTP 422nothing_to_updateThe PATCH request has no fields to change.
HTTP 429rate_limitedPer-minute rate limit exceeded — wait Retry-After seconds.
HTTP 429too_many_auth_failuresMore than 30 failed sign-ins per minute or 300 per hour from one IP (no token, a wrong token, or a non-allowlisted IP) — requests from that IP are refused until the window ends; the wait is in Retry-After.
HTTP 429daily_limit, hourly_limitThe daily spend limit or the hourly purchase limit of the key is used up.
HTTP 429busyAnother purchase is in progress — retry in a few seconds with the same Idempotency-Key.
HTTP 429ai_rate_limitedAI generation limit, or too many generations at once — retry after Retry-After seconds. The listing stays for sale meanwhile.
HTTP 500internal_errorFailure on our side. Retry purchases with the same Idempotency-Key.
HTTP 502ai_failedThe model gave no usable description — the listing keeps its previous text (the AI description if it had one, otherwise the rule-based description); try again later.
HTTP 503api_disabled, market_disabledThe API or the domain marketplace is temporarily disabled.
HTTP 503ai_unavailableAI descriptions are off right now — buyers see the rule-based description.

Endpoints

Paths are relative to the base URL https://hqclouds.com/api/v1.

GET /me

Account, balance and key

Who owns the token, how much money is on the balance, which scopes the key has and how much of the daily limit is already spent. Handy for checking a token before you start.

Scope: read

Request

bash
curl -s https://hqclouds.com/api/v1/me \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "user": {"id": "6f1c2a9e-3b7d-4e2a-9c51-8d0f2b7a4e13", "email": "you@example.com"},
  "balance": {"amount": "120.50", "currency": "USD"},
  "key": {
    "id": "key_4b2f9a1c7d3e5f60a1b2c3d4",
    "name": "HQName",
    "scopes": ["read", "domains:register", "market:write"],
    "daily_spend_limit": "100.00",
    "spent_24h": "12.99",
    "rate_limit_per_minute": 60,
    "expires_at": null,
    "ip_allowlist": ["203.0.113.7"]
  }
}
GET /domains/check

Check a domain

Whether a domain is available and how much registration and renewal cost. Buys nothing. If the domain is for sale in the HQClouds marketplace, for_sale contains the price and a link.

Scope: read

Parameter Type Required Description
domain string yes Domain name, e.g. example.com. Internationalized (non-Latin) domains are accepted as is.
  • state: available — free, taken — registered, premium — premium domain (not sold via the API), for_sale — for sale in the HQClouds marketplace, unsupported_tld — we do not register this zone, unknown — could not check, retry later.
  • Availability is indicative: the final price and availability check happens at purchase.

Request

bash
curl -s "https://hqclouds.com/api/v1/domains/check?domain=example.com" \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "domain": "example.com",
  "state": "available",
  "available": true,
  "premium": false,
  "price": {"register": "12.99", "renew": "14.99", "currency": "USD"},
  "for_sale": null,
  "note": "Availability is indicative; the final check happens at purchase."
}
POST /domains/register

Buy a domain

Registers a domain for 1 year and charges the price to your HQClouds balance. Before charging, the same final price check runs as on the website. Purchases are processed one at a time. Buying does not list anything for sale: listing is a separate POST /market/lots request.

Scope: domains:register

Parameter Type Required Description
Idempotency-Key header yes A unique string per purchase (up to 100 characters). See “Idempotent purchases” for details.
domain string yes Domain name.
max_price number no Do not buy if the final price is above this amount, USD: a plain number, for example 15 or 14.99. We recommend always sending it.
years integer no Registration period. Only 1 year is available via the API.
  • Before your first purchase, fill in the domain owner contacts (WHOIS) in your dashboard once — without them you get 409 no_contact.
  • 201 — the domain is registered and already yours. 202 — the registrar is still processing the order: the money is reserved; do not buy again, but check GET /domains/{domain} every minute or two until status becomes active (the domain is yours) or failed (it did not work out, the money is back on your balance).
  • 409 registration_failed — the registrar refused after the reservation: the money is back on your balance (refunded: true) and the daily limit reservation is released. This outcome is final: nothing will be charged for this request later, and you can start a new purchase of the same domain right away (with a new Idempotency-Key). Other refusals (domain taken, price above max_price) do not charge anything either.
  • If an attempt reached the registrar, a retry with the same Idempotency-Key returns its outcome marked idempotent_replay: true — 201 with the price, 202 or 409 registration_failed — and charges nothing. A refusal before the registrar (domain taken, balance, max_price, limit) can be retried with the same key.
  • The order number is order.id (dq_…): it is in every response where the purchase reached the registrar (201, 202, 409 registration_failed) and stays the same when you retry with the same Idempotency-Key. GET /orders/{id} shows its outcome, and POST /market/lots with order_id lists the purchased domain. A refusal before the money is reserved has no order number — there was no order.
  • One amount: the price is checked when the request arrives (not above max_price) and once more when the money is reserved. If it rose in between, nothing is bought: 409 price_changed with the new price in error.price and the price checked on arrival in error.confirmed_price; nothing is charged. If the new price is not above what the user confirmed, repeat with the same Idempotency-Key; if it is higher, ask the user first. If it dropped, the lower price is charged. price in responses, the order amount and the daily-limit spend are exactly what was reserved or charged.
  • registration — how the domain was registered: mode live (at the real registrar) or sandbox (the platform’s test mode: the registration is simulated and the domain does not exist at the registrar, although the money is charged from the balance), years — the term (always 1 via the API), real — true only for live. With real: false, do not tell the user the domain is theirs: such a domain cannot be listed for sale (409 domain_not_real).
  • If the response was lost (timeout, dropped connection) and you do not know the order number, ask GET /domains/register/{Idempotency-Key}: it buys and charges nothing.
  • A repeat after a refusal before the registrar or after 404 not_started is a new attempt: the price and the spend limits are checked again. The Idempotency-Key is bound to the domain from the first attempt: the same key with another domain gives 422 idempotency_key_reused.
  • The Idempotency-Key is scoped to the account: a repeat with another API key of the same account (for example, after a key rotation) returns the same purchase marked other_api_key: true instead of buying a second time.

Request

bash
curl -s -X POST https://hqclouds.com/api/v1/domains/register \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: buy-example-com-20261001" \
  -d '{"domain":"example.com","max_price":15}'

Response

201 Created
{
  "ok": true,
  "status": "registered",
  "price": "12.99",
  "currency": "USD",
  "registration": {"mode": "live", "years": 1, "real": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "registered"},
  "domain": {
    "id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a",
    "domain": "example.com",
    "status": "active",
    "expires_at": "2027-10-01 09:14:52",
    "auto_renew": true,
    "parked": false,
    "nameservers": [],
    "registration": {"mode": "live", "years": 1, "real": true},
    "listing": null
  }
}
202 Accepted
{
  "ok": true,
  "status": "pending",
  "price": "12.99",
  "currency": "USD",
  "domain_name": "example.com",
  "message": "The registrar is still processing the order. Check GET /api/v1/domains/example.com in a few minutes.",
  "registration": {"mode": "live", "years": 1, "real": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "pending"}
}
409 Conflict
{
  "ok": false,
  "error": {
    "code": "registration_failed",
    "message": "Registration failed, the money was returned to your balance.",
    "domain": "example.com",
    "refunded": true
  },
  "registration": {"mode": "live", "years": 1, "real": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "failed"}
}
409 Conflict — the price rose between the checks
{
  "ok": false,
  "error": {
    "code": "price_changed",
    "message": "The price changed: $13.99 instead of the confirmed $12.99. Nothing was charged — confirm the new price and buy again.",
    "domain": "example.com",
    "price": "13.99",
    "confirmed_price": "12.99",
    "charged": false,
    "max_price": "15.00"
  }
}
201 Created — test mode (sandbox), not a real domain (domain fields shortened)
{
  "ok": true,
  "status": "registered",
  "price": "12.99",
  "currency": "USD",
  "registration": {
    "mode": "sandbox",
    "years": 1,
    "real": false,
    "note": "Test mode (sandbox): the domain was NOT registered at the registrar — this is a simulated purchase. Do not tell the user the domain is theirs and do not list it for sale."
  },
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "registered"},
  "domain": {
    "id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a",
    "domain": "example.com",
    "status": "active",
    "registration": {"mode": "sandbox", "years": 1, "real": false, "note": "Test mode (sandbox): the domain was NOT registered at the registrar — …"}
  }
}
GET /domains/register/{idempotency_key}

How a purchase ended (by Idempotency-Key)

Reconciliation after a lost response: the POST /domains/register response never arrived and you do not know the order number — but you knew the Idempotency-Key before sending. Read-only: this request buys nothing, charges nothing and does not contact the registrar.

Scope: read

Parameter Type Required Description
idempotency_key path yes The same Idempotency-Key that was in the purchase header. It is looked up across the whole account: a purchase made with another API key of the account (for example, before a key rotation) is found too, marked other_api_key: true.
  • 200 — the order exists: order is the same object as in GET /orders/{id} (status pending, registered or failed, refunded, the charged amount price, registration, domain_service, listing). While status is pending, there is a Retry-After header.
  • 202 in_progress — a purchase with this key is still running: ask again after Retry-After seconds and do not start a new purchase.
  • 404 not_started — the purchase never reached the registrar (or was refused before any money was reserved): nothing was charged. Send POST /domains/register with the SAME Idempotency-Key — if the first attempt made it after all, the repeat returns its result instead of buying a second time.

Request

bash
curl -s https://hqclouds.com/api/v1/domains/register/buy-example-com-20261001 \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK (order fields shortened)
{
  "ok": true,
  "idempotency_key": "buy-example-com-20261001",
  "order": {
    "id": "dq_5adc8ffc18cbcba5c488dd9e",
    "type": "domain_register",
    "domain": "example.com",
    "status": "registered",
    "refunded": false,
    "price": "12.99",
    "currency": "USD",
    "registration": {"mode": "live", "years": 1, "real": true},
    "domain_service": {"id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a", "domain": "example.com", "status": "active"},
    "listing": null,
    "can_list": true,
    "next": {"action": "list_on_market", "method": "POST", "path": "/api/v1/market/lots", "body": {"order_id": "dq_5adc8ffc18cbcba5c488dd9e"}}
  }
}
202 Accepted
{
  "ok": true,
  "status": "in_progress",
  "idempotency_key": "buy-example-com-20261001",
  "retry_after": 5,
  "message": "A purchase with this key is still running — ask again in a few seconds. Do not start a new purchase."
}
404 Not Found
{
  "ok": false,
  "error": {
    "code": "not_started",
    "message": "The purchase with this key never reached the registrar: nothing was charged and no domain was ordered. Send POST /api/v1/domains/register with the SAME Idempotency-Key — it will not create a second purchase.",
    "idempotency_key": "buy-example-com-20261001",
    "charged": false
  }
}
GET /domains

My domains

All domains of the account, paginated. can_list — whether the domain can be listed for sale right now, list_blocked_reason — why not, listing — the current listing if the domain is already for sale.

Scope: read

Parameter Type Required Description
page integer no Page number, starting from 1.
per_page integer no Page size: 50 by default, 100 max.

Request

bash
curl -s "https://hqclouds.com/api/v1/domains?page=1&per_page=50" \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "items": [
    {
      "id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a",
      "domain": "example.com",
      "status": "active",
      "expires_at": "2027-10-01 09:14:52",
      "auto_renew": true,
      "parked": true,
      "nameservers": ["ns1.hqclouds.com", "ns2.hqclouds.com"],
      "registration": {"mode": "live", "years": 1, "real": true},
      "listing": null,
      "can_list": true,
      "list_blocked_reason": null
    }
  ],
  "total": 1,
  "page": 1,
  "pages": 1,
  "per_page": 50
}
GET /domains/{domain}

Single domain

Status, paid-until date, nameservers and current listing of one domain. Use the same request to wait for the domain after a 202 response.

Scope: read

Parameter Type Required Description
domain path yes Domain name in the path.
  • Until the domain is issued after a 202, the response is 200 with "domain": null and status: pending. If registration failed — status: failed and refunded: true, the money is back on your balance. 404 — there is neither the domain nor an attempt to buy it.
  • registration.real: false — the domain was bought in test mode (sandbox): it does not exist at the registrar.

Request

bash
curl -s https://hqclouds.com/api/v1/domains/example.com \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "domain": {
    "id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a",
    "domain": "example.com",
    "status": "active",
    "expires_at": "2027-10-01 09:14:52",
    "auto_renew": true,
    "parked": false,
    "nameservers": [],
    "registration": {"mode": "live", "years": 1, "real": true},
    "listing": {
      "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
      "price": "249.00",
      "status": "listed",
      "url": "https://hqclouds.com/market/example.com?lang=en"
    }
  }
}
200 OK — registration in progress
{
  "ok": true,
  "domain": null,
  "domain_name": "example.com",
  "status": "pending",
  "message": "The registrar is still processing the order. Check GET /api/v1/domains/example.com in a few minutes.",
  "registration": {"mode": "live", "years": 1, "real": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "pending"}
}
200 OK — registration failed
{
  "ok": true,
  "domain": null,
  "domain_name": "example.com",
  "status": "failed",
  "refunded": true,
  "message": "Registration failed, the money was returned to your balance.",
  "registration": {"mode": "live", "years": 1, "real": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "failed"}
}
GET /orders

My orders

Domain purchases that reached the registrar, newest first (last 5000): made via the API and on the website. Each items element is an order object, as in GET /orders/{id}.

Scope: read

Parameter Type Required Description
status string no Filter: pending (the registrar is still working), registered (the domain is bought), failed (it failed, the money was returned).
page integer no Page number, starting from 1.
per_page integer no Page size: 50 by default, 100 max.

Request

bash
curl -s "https://hqclouds.com/api/v1/orders?status=registered" \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK (order fields shortened)
{
  "ok": true,
  "items": [
    {
      "id": "dq_5adc8ffc18cbcba5c488dd9e",
      "type": "domain_register",
      "domain": "example.com",
      "status": "registered",
      "refunded": false,
      "price": "12.99",
      "currency": "USD",
      "registration": {"mode": "live", "years": 1, "real": true},
      "can_list": true
    }
  ],
  "total": 1,
  "page": 1,
  "pages": 1,
  "per_page": 50
}
GET /orders/{id}

One order

The purchase outcome by the order number from the POST /domains/register response: status pending, registered or failed. It also shows the domain service, the current listing and the next hint: what to do next.

Scope: read

Parameter Type Required Description
id path yes Order number (order.id, dq_…).
  • status: pending — the registrar is still working and the money is reserved: ask again after Retry-After seconds (such responses carry this header). registered — the domain is bought. failed — registration failed and the money was returned to your balance (refunded: true).
  • domain_service — the domain in your account; null until the order is registered or if the domain is no longer yours (sold, transferred, deleted). listing — your live listing of this domain. can_list and list_blocked_reason — whether the domain can be listed now and why not.
  • next — the next step: wait (wait and ask again), list_on_market (list it: the method, path and request body are ready), manage_listing (the domain is already for sale) or null — nothing to do.
  • Someone else’s or an unknown number returns 404 order_not_found: the API never confirms that other people’s orders exist. The price is what you were charged (or what is reserved), without our cost.
  • registration — how the domain was registered (mode live or sandbox, years, real), as in the purchase response. A sandbox order has can_list: false — a test domain cannot be listed.

Request

bash
curl -s https://hqclouds.com/api/v1/orders/dq_5adc8ffc18cbcba5c488dd9e \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "order": {
    "id": "dq_5adc8ffc18cbcba5c488dd9e",
    "type": "domain_register",
    "domain": "example.com",
    "domain_display": "example.com",
    "status": "registered",
    "refunded": false,
    "price": "12.99",
    "currency": "USD",
    "registration": {"mode": "live", "years": 1, "real": true},
    "created_at": "2026-10-01 09:14:40",
    "updated_at": "2026-10-01 09:14:52",
    "domain_service": {
      "id": "svc_9d3a1f0b2c4e6a8b0d1f3e5a",
      "domain": "example.com",
      "status": "active",
      "expires_at": "2027-10-01 09:14:52",
      "auto_renew": true,
      "parked": true,
      "nameservers": ["ns1.hqclouds.com", "ns2.hqclouds.com"],
      "registration": {"mode": "live", "years": 1, "real": true},
      "listing": null
    },
    "listing": null,
    "can_list": true,
    "list_blocked_reason": null,
    "next": {
      "action": "list_on_market",
      "method": "POST",
      "path": "/api/v1/market/lots",
      "body": {"order_id": "dq_5adc8ffc18cbcba5c488dd9e"},
      "message": "The domain is yours: list it for sale with POST /api/v1/market/lots and order_id."
    }
  }
}
200 OK — registration in progress
{
  "ok": true,
  "order": {
    "id": "dq_5adc8ffc18cbcba5c488dd9e",
    "type": "domain_register",
    "domain": "example.com",
    "domain_display": "example.com",
    "status": "pending",
    "refunded": false,
    "price": "12.99",
    "currency": "USD",
    "registration": {"mode": "live", "years": 1, "real": true},
    "created_at": "2026-10-01 09:14:40",
    "updated_at": "2026-10-01 09:14:40",
    "domain_service": null,
    "listing": null,
    "can_list": false,
    "list_blocked_reason": null,
    "next": {
      "action": "wait",
      "method": "GET",
      "path": "/api/v1/orders/dq_5adc8ffc18cbcba5c488dd9e",
      "retry_after": 60,
      "message": "The registrar is still processing the order: ask again in a minute."
    }
  }
}
GET /market/lots

My listings

Your listings in the domain marketplace, newest first (last 1000). Each items element is a listing object, as in the listing response: with the card and the AI description state ai.

Scope: read

Parameter Type Required Description
status string no Filter: active (for sale or reserved), listed, reserved, sold, delisted, cancelled.
page integer no Page number, starting from 1.
per_page integer no Page size: 50 by default, 100 max.
  • Listing status: for_sale — for sale, reserved — a buyer is paying an invoice, sold — sold, unavailable — removed from sale. raw_status — the exact status: listed, reserved, sold, delisted (removed by you), cancelled (removed by the system: the domain expired or left your account).
  • cancel_reason — why the system took the listing down (cancelled only): expiring — the domain expires soon, owner_changed — the domain left the account, service_missing or service_<status> — the domain service is missing or not active. null for other listings. sandbox — the domain was bought in test mode and does not exist at the registrar.

Request

bash
curl -s "https://hqclouds.com/api/v1/market/lots?status=active" \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK (listing fields shortened)
{
  "ok": true,
  "items": [
    {
      "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
      "domain": "example.com",
      "price": "249.00",
      "status": "for_sale",
      "raw_status": "listed",
      "views": 12,
      "url": "https://hqclouds.com/market/example.com?lang=en",
      "ai": {"status": "queued", "attempts": 0}
    }
  ],
  "total": 1,
  "page": 1,
  "pages": 1,
  "per_page": 50
}
POST /market/lots

List a domain for sale

Creates a listing in the domain marketplace. The domain must be in your HQClouds account, active, paid for at least 30 more days and have no pending registrar operations.

Scope: market:write

Parameter Type Required Description
domain string no A domain from your account. Send domain or order_id — one of the two.
order_id string no The order number from the purchase response (order.id): lists the purchased domain without repeating its name. Order still pending — 409 order_pending with Retry-After, failed — 409 order_failed, the domain is no longer yours — 409 domain_not_owned, someone else’s or an unknown number — 404 order_not_found. A domain from a test (sandbox) purchase — 409 domain_not_real: it does not exist at the registrar. The same goes for a lot listed earlier: 409 domain_not_real instead of already_listed, and the lot itself is taken down automatically (cancel_reason: sandbox).
price number no Price in USD: from $5 to $100,000. If omitted — the default price, $50.
category string no Theme — a key from the table below. If omitted, we detect it from the domain name.
tags array | string no Up to 10 tags: an array or a comma-separated string. A tag is letters, digits, spaces or hyphens, up to 30 characters; a leading “#” is removed and “_” becomes “-”. An invalid tag returns 422 invalid_field with the rejected list. If omitted, we derive them from the name (cloud, pay, ai…).
headline string no Headline, up to 160 characters. If omitted, buyers see an auto-generated text in their language.
description string no Description, up to 2000 characters. If omitted — an auto-generated text in the buyer’s language.
describe string no AI description: auto (the default) — if AI descriptions are enabled, we make it in the background within a few minutes; ai — generate it now, in the same request: usually 5–30 seconds, at most ~45 seconds (set a client timeout of 60 seconds). An AI failure, a limit or AI being off does not block the listing: the listing is created and ai has status: failed with the reason code.
metadata object no Your own data, for example a domain score from HQName: up to 20 fields; keys — Latin letters, digits and _ (up to 40 characters); values — a string up to 300 characters, a number, true/false or null. Returned in responses exactly as sent; breaking the rules gives 422 invalid_field.
  • On sale the marketplace keeps a 10% commission; the rest is credited to your HQClouds balance right away.
  • Repeating the request for a domain that is already listed returns 200 and the same listing with already_listed: true, unchanged (use PATCH to change it). A new listing returns 201. A script retry will not break anything.
  • domain or order_id is enough: the price, category, tags and text are filled in automatically. card is the listing card exactly as a buyer sees it in the response language (?lang= or Accept-Language): headline, description, “good fit for” list, category, tags, link and preview image.
  • card.text_source — where the text comes from: seller (you wrote it), ai (AI description) or rules (automatic description from the name). Your headline and description always win over AI: AI only fills empty fields. The top-level headline and description are what you wrote (null means automatic text).
  • card.pronunciation — how the name is read: ipa, en (English respelling, stressed syllable in capitals), ru (Russian transcription); source: ai — from AI, rules — approximate, from reading rules (approx: true, no IPA and no stress; a respelling identical to the name itself is an empty string, and for names with digits or very long names pronunciation is null). card.meaning — the parts of the name and their origin, card.translations — the meaning of the name in en, ru, de, es, fr, it, pt, zh, ja (empty for invented names), card.language_notes — notes on how the name sounds in major languages (usually empty).
  • card.score — the “HQ score” 0–100: points for the name itself by HQClouds rules (length, sound, memorability, spelling, zone, meaning — taking card.meaning into account) with a hint for each part. It is not a price or an appraisal. The same fields, without labels, are also at the top level of the lot.
  • ai — the AI description state, always one of four statuses: ready (done, languages lists the languages), queued (we will make it in the background; with code: ai_in_progress it is already being generated by another request), disabled (it will not appear by itself, reason says why: ai_off — AI descriptions are off on the platform, auto_off — background generation is off, request it via /describe, lot_not_active — the listing is not for sale), failed (it did not work — code and reason say why). Until there is AI text, buyers see the rule-based description.
  • If the describe: "ai" response did not arrive (timeout, 502 or 504 from a proxy), the listing is already created: check GET /market/lots/{domain} — ai.status becomes ready when the text is done. Repeating the request is safe too: it returns the same listing, and while a generation is running there will not be a second one.
  • The three statuses are independent: order.status — the purchase, lot.status — the listing, ai.status — the AI description. An AI failure does not undo the listing (the lot is created — 201 with ai.status: failed) and never starts a purchase: this request moves no money.

Request

bash
curl -s -X POST https://hqclouds.com/api/v1/market/lots \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"dq_5adc8ffc18cbcba5c488dd9e","price":"249","category":"tech","tags":["short","brandable"],"describe":"ai","metadata":{"source":"hqname","score":87}}'

Response

201 Created
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "domain_display": "example.com",
    "sld": "example",
    "tld": ".com",
    "length": 7,
    "has_digits": false,
    "has_hyphen": false,
    "price": "249.00",
    "currency": "USD",
    "status": "for_sale",
    "category": "tech",
    "category_label": "Technology",
    "tags": ["short", "brandable"],
    "headline": null,
    "description": null,
    "headline_text": "A short, crisp name for a tech product",
    "description_text": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
    "text_auto": true,
    "text_source": "ai",
    "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
    "paid_until": "2027-10-01",
    "listed_at": "2026-10-01",
    "views": 0,
    "raw_status": "listed",
    "source": "api",
    "reserved_until": null,
    "sold_at": null,
    "delisted_at": null,
    "cancel_reason": null,
    "metadata": {"score": 87, "source": "hqname"},
    "url": "https://hqclouds.com/market/example.com?lang=en",
    "card": {
      "domain": "example.com",
      "price": "249.00",
      "currency": "USD",
      "headline": "A short, crisp name for a tech product",
      "description": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
      "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
      "category": "tech",
      "category_label": "Technology",
      "tags": ["short", "brandable"],
      "text_source": "ai",
      "ai_languages": ["en", "ru"],
      "language": "en",
      "url": "https://hqclouds.com/market/example.com?lang=en",
      "og_image": "https://hqclouds.com/market/example.com/og?lang=en",
      "pronunciation": {"ipa": "/ɪɡˈzɑːm.pəl/", "en": "ig-ZAHM-pul", "ru": "иг-ЗАМ-пл", "latin": null, "source": "ai", "approx": false},
      "meaning": [{"part": "example", "lang_ru": "английский", "lang_en": "English", "ru": "пример", "en": "example"}],
      "translations": [{"lang": "ru", "text": "пример"}, {"lang": "de", "text": "Beispiel"}, {"lang": "ja", "text": "例"}],
      "language_notes": [],
      "score": {
        "total": 95, "max": 100, "grade": "excellent", "grade_label": "excellent", "version": 2,
        "parts": [
          {"key": "length", "score": 20, "max": 20, "hint": "length_sweet", "label": "Length", "hint_text": "5 to 8 characters — a handy length for a brand."},
          {"key": "sound", "score": 16, "max": 20, "hint": "sound_cluster", "label": "Sound", "hint_text": "A consonant cluster makes it harder to say."}
        ]
      }
    },
    "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41", "cached": false}
  },
  "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41", "cached": false},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "registered"}
}
201 Created — lot listed, the AI description failed (lot fields shortened)
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "price": "50.00",
    "currency": "USD",
    "status": "for_sale",
    "raw_status": "listed",
    "url": "https://hqclouds.com/market/example.com?lang=en",
    "card": {"headline": "Ready-made name for a mobile app", "text_source": "rules", "ai_languages": []},
    "ai": {"status": "failed", "code": "ai_failed", "reason": "error", "message": "Could not generate a description — try again later. The rule-based description is shown meanwhile."}
  },
  "ai": {"status": "failed", "code": "ai_failed", "reason": "error", "message": "Could not generate a description — try again later. The rule-based description is shown meanwhile."},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "registered"}
}
200 OK — the domain is already listed (listing fields shortened)
{
  "ok": true,
  "already_listed": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "price": "249.00",
    "status": "for_sale",
    "raw_status": "listed",
    "url": "https://hqclouds.com/market/example.com?lang=en"
  },
  "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41", "cached": true},
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "registered"}
}
409 Conflict
{
  "ok": false,
  "error": {
    "code": "order_pending",
    "message": "The registrar is still processing the order — the domain can be listed once it is registered. Retry in a minute.",
    "retry_after": 60
  },
  "order": {"id": "dq_5adc8ffc18cbcba5c488dd9e", "status": "pending"}
}
GET /market/lots/{domain}

Single listing

A listing by domain name or listing id (lot_…). If the domain was listed several times, the live listing is returned, otherwise the latest one.

Scope: read

Parameter Type Required Description
domain path yes Domain name or listing id.

Request

bash
curl -s https://hqclouds.com/api/v1/market/lots/example.com \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "domain_display": "example.com",
    "sld": "example",
    "tld": ".com",
    "length": 7,
    "has_digits": false,
    "has_hyphen": false,
    "price": "249.00",
    "currency": "USD",
    "status": "for_sale",
    "category": "tech",
    "category_label": "Technology",
    "tags": ["short", "brandable"],
    "headline": null,
    "description": null,
    "headline_text": "A short, crisp name for a tech product",
    "description_text": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
    "text_auto": true,
    "text_source": "ai",
    "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
    "paid_until": "2027-10-01",
    "listed_at": "2026-10-01",
    "views": 0,
    "raw_status": "listed",
    "source": "api",
    "reserved_until": null,
    "sold_at": null,
    "delisted_at": null,
    "cancel_reason": null,
    "metadata": {"score": 87, "source": "hqname"},
    "url": "https://hqclouds.com/market/example.com?lang=en",
    "card": {
      "domain": "example.com",
      "price": "249.00",
      "currency": "USD",
      "headline": "A short, crisp name for a tech product",
      "description": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
      "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
      "category": "tech",
      "category_label": "Technology",
      "tags": ["short", "brandable"],
      "text_source": "ai",
      "ai_languages": ["en", "ru"],
      "language": "en",
      "url": "https://hqclouds.com/market/example.com?lang=en",
      "og_image": "https://hqclouds.com/market/example.com/og?lang=en",
      "pronunciation": {"ipa": "/ɪɡˈzɑːm.pəl/", "en": "ig-ZAHM-pul", "ru": "иг-ЗАМ-пл", "latin": null, "source": "ai", "approx": false},
      "meaning": [{"part": "example", "lang_ru": "английский", "lang_en": "English", "ru": "пример", "en": "example"}],
      "translations": [{"lang": "ru", "text": "пример"}, {"lang": "de", "text": "Beispiel"}, {"lang": "ja", "text": "例"}],
      "language_notes": [],
      "score": {
        "total": 95, "max": 100, "grade": "excellent", "grade_label": "excellent", "version": 2,
        "parts": [
          {"key": "length", "score": 20, "max": 20, "hint": "length_sweet", "label": "Length", "hint_text": "5 to 8 characters — a handy length for a brand."},
          {"key": "sound", "score": 16, "max": 20, "hint": "sound_cluster", "label": "Sound", "hint_text": "A consonant cluster makes it harder to say."}
        ]
      }
    },
    "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41"}
  },
  "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41"}
}
PATCH /market/lots/{domain}

Update a listing

Send only the fields you change: price, category, tags, headline, description, metadata. null or an empty string clears a field (except the price): the category and tags are detected automatically again, and the headline and description go back to the automatic description (AI or rule-based).

Scope: market:write

Parameter Type Required Description
domain path yes Domain name or listing id.
price number no New price in USD.
category, tags no As when listing; null or "" means detect automatically.
headline, description string | null no Your text — it always wins over AI. null or "" brings back the automatic description.
metadata object no Replaces your metadata entirely; null or {} clears it. Same rules as when listing.
describe string no ai — right after saving, make the AI description if there is none yet; if this same edit changed the category or tags, write it again for the new theme. To regenerate without edits, use POST …/describe with force. Can be sent without other fields.
  • While a buyer is paying for the domain (reserved), the listing cannot be edited, delisted or regenerated — 409 lot_reserved; once the reservation ends you can. A delisted or sold listing returns 409 lot_not_active.
  • The response is the whole listing with the updated card: it shows what a buyer will see now.

Request

bash
curl -s -X PATCH https://hqclouds.com/api/v1/market/lots/example.com \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"price":"199.00","headline":"Short brandable .com","description":null}'

Response

200 OK (listing fields shortened)
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "price": "199.00",
    "status": "for_sale",
    "raw_status": "listed",
    "headline": "Short brandable .com",
    "description": null,
    "url": "https://hqclouds.com/market/example.com?lang=en",
    "card": {
      "headline": "Short brandable .com",
      "description": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
      "text_source": "ai"
    }
  },
  "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41"}
}
POST /market/lots/{domain}/describe

AI listing description

Generates the AI description of the listing now, in the same request: the headline, description and “good fit for” list in Russian and English; it also refines the automatic category and tags. Usually 5–30 seconds, at most ~45 seconds: set a client timeout of 60 seconds. Within this request the model answers once: an unusable answer is 502 ai_failed (reason: rejected) — retry later. The platform retries by itself (with automatic descriptions on) only for a listing that has no AI text yet; a failed regeneration (force) keeps the previous AI text — retry it yourself.

Scope: market:write

Parameter Type Required Description
domain path yes Domain name or listing id.
force boolean no true — generate again even if an AI description already exists. Without force an existing description is returned immediately (cached: true) and the generation limit is not used.
  • AI never overwrites your headline and description: they always win, and AI text only shows in empty fields. AI does not touch the category and tags you chose either.
  • Refusals: 503 ai_unavailable — AI descriptions are off; 429 ai_rate_limited — generation limit, or 2 generations of your listings are already running (reason: user_concurrency), retry after Retry-After seconds; 409 ai_in_progress — this listing is already being generated by another request; 502 ai_failed — the model gave no usable text. In every case the listing stays for sale with its previous text: the AI description if it already had one, otherwise the rule-based description.
  • Only for listings that are for sale: a delisted or sold listing returns 409 lot_not_active, one reserved by a buyer returns 409 lot_reserved.
  • If the response did not arrive (timeout), do not request it again: check GET /market/lots/{domain} — ai.status becomes ready when the text is done. A retry while the first generation is running returns 409 ai_in_progress and does not pay for a second one.

Request

bash
curl -s -X POST https://hqclouds.com/api/v1/market/lots/example.com/describe \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"force":true}'

Response

200 OK
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "domain_display": "example.com",
    "sld": "example",
    "tld": ".com",
    "length": 7,
    "has_digits": false,
    "has_hyphen": false,
    "price": "249.00",
    "currency": "USD",
    "status": "for_sale",
    "category": "tech",
    "category_label": "Technology",
    "tags": ["short", "brandable"],
    "headline": null,
    "description": null,
    "headline_text": "A short, crisp name for a tech product",
    "description_text": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
    "text_auto": true,
    "text_source": "ai",
    "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
    "paid_until": "2027-10-01",
    "listed_at": "2026-10-01",
    "views": 0,
    "raw_status": "listed",
    "source": "api",
    "reserved_until": null,
    "sold_at": null,
    "delisted_at": null,
    "cancel_reason": null,
    "metadata": {"score": 87, "source": "hqname"},
    "url": "https://hqclouds.com/market/example.com?lang=en",
    "card": {
      "domain": "example.com",
      "price": "249.00",
      "currency": "USD",
      "headline": "A short, crisp name for a tech product",
      "description": "Seven letters and three syllables: easy to say, spell and remember. The .com ending is what customers type first. A good fit for a SaaS product, a developer tool or an AI assistant.",
      "use_cases": ["SaaS startup", "developer tool", "AI assistant"],
      "category": "tech",
      "category_label": "Technology",
      "tags": ["short", "brandable"],
      "text_source": "ai",
      "ai_languages": ["en", "ru"],
      "language": "en",
      "url": "https://hqclouds.com/market/example.com?lang=en",
      "og_image": "https://hqclouds.com/market/example.com/og?lang=en",
      "pronunciation": {"ipa": "/ɪɡˈzɑːm.pəl/", "en": "ig-ZAHM-pul", "ru": "иг-ЗАМ-пл", "latin": null, "source": "ai", "approx": false},
      "meaning": [{"part": "example", "lang_ru": "английский", "lang_en": "English", "ru": "пример", "en": "example"}],
      "translations": [{"lang": "ru", "text": "пример"}, {"lang": "de", "text": "Beispiel"}, {"lang": "ja", "text": "例"}],
      "language_notes": [],
      "score": {
        "total": 95, "max": 100, "grade": "excellent", "grade_label": "excellent", "version": 2,
        "parts": [
          {"key": "length", "score": 20, "max": 20, "hint": "length_sweet", "label": "Length", "hint_text": "5 to 8 characters — a handy length for a brand."},
          {"key": "sound", "score": 16, "max": 20, "hint": "sound_cluster", "label": "Sound", "hint_text": "A consonant cluster makes it harder to say."}
        ]
      }
    },
    "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41", "cached": false}
  },
  "ai": {"status": "ready", "languages": ["en", "ru"], "generated_at": "2026-10-01 12:00:41", "cached": false}
}
429 Too Many Requests
{
  "ok": false,
  "error": {
    "code": "ai_rate_limited",
    "message": "AI generation limit reached — try again later.",
    "reason": "user_hour_limit",
    "retry_after": 1200
  }
}
DELETE /market/lots/{domain}

Remove from sale

Removes the listing from the marketplace. Calling it again is safe: it returns the already removed listing.

Scope: market:write

Parameter Type Required Description
domain path yes Domain name or listing id.
  • While a buyer is paying for the domain (reserved), the listing cannot be delisted — 409 lot_reserved; once the reservation ends you can.

Request

bash
curl -s -X DELETE https://hqclouds.com/api/v1/market/lots/example.com \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK (listing fields shortened)
{
  "ok": true,
  "lot": {
    "id": "lot_1a2b3c4d5e6f7a8b9c0d1e2f",
    "domain": "example.com",
    "status": "unavailable",
    "raw_status": "delisted",
    "delisted_at": "2026-10-01 12:30:00",
    "url": "https://hqclouds.com/market/example.com?lang=en"
  }
}
GET /market/sales

Sales history

Completed sales, newest first (last 5000), plus account totals.

Scope: read

Parameter Type Required Description
page integer no Page number, starting from 1.
per_page integer no Page size: 50 by default, 100 max.
  • stats: sold — domains sold, revenue — total sales, commission — marketplace commission, proceeds — credited to your balance, listed — currently for sale, views — views of active listings.

Request

bash
curl -s https://hqclouds.com/api/v1/market/sales \
  -H "Authorization: Bearer $HQC_TOKEN"

Response

200 OK
{
  "ok": true,
  "stats": {
    "sold": 3,
    "revenue": "747.00",
    "commission": "74.70",
    "proceeds": "672.30",
    "listed": 5,
    "views": 214
  },
  "items": [
    {
      "id": "mko_7c1e3a5b9d0f2a4c6e8b1d3f",
      "domain": "example.com",
      "price": "249.00",
      "commission": "24.90",
      "proceeds": "224.10",
      "currency": "USD",
      "sold_at": "2026-09-28 14:03:11"
    }
  ],
  "total": 3,
  "page": 1,
  "pages": 1,
  "per_page": 50
}

Listing categories (category, theme)

brand Brandable tech Technology ai AI business Business finance Finance crypto Crypto ecommerce Shopping creative Creative social Community health Health education Education travel Travel food Food realestate Real Estate fun Hobbies & Games

Scenario: buy and list right away

The whole path in one script — this is how the HQName integration works: find a good name, buy it from your balance, get the order number and use it to list the domain in the HQClouds marketplace with an AI description right away. Then edit and delist the same listing.

bash
export HQC_TOKEN="hqc_xxxxxxxx_..."
DOMAIN="example.com"
# Purchase key: one per purchase. The script prints it — rerunning with KEY=<the same> continues the same purchase instead of starting a new one.
KEY="${KEY:-$(uuidgen)}"
echo "Idempotency-Key: $KEY" >&2

# 1. Buy the domain. The response has the order number order.id. A network error, 5xx, busy or 429 means a retry with the same KEY: you will not be charged twice. Any other refusal (domain taken, balance, max_price) exits.
# price_changed — the price rose between the checks and nothing was charged: ask the user again. To learn the outcome without buying — GET /domains/register/$KEY.
for TRY in 1 2 3 4 5; do
  RESP=$(curl -s -X POST https://hqclouds.com/api/v1/domains/register \
    -H "Authorization: Bearer $HQC_TOKEN" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $KEY" \
    -d "{\"domain\":\"$DOMAIN\",\"max_price\":15}")
  ORDER=$(echo "$RESP" | jq -r '.order.id // empty' 2>/dev/null)
  [ -n "$ORDER" ] && break
  CODE=$(echo "$RESP" | jq -r '.error.code // empty' 2>/dev/null)
  case "$CODE" in ""|busy|rate_limited|internal_error) sleep 15 ;; *) echo "$CODE" >&2; exit 1 ;; esac
done
[ -n "$ORDER" ] || { echo "no order, KEY=$KEY" >&2; exit 1; }

# 2. Wait for the outcome: GET /orders/{id} once a minute until status is registered or failed. A network error, 429 or 5xx means another attempt; any other error (token revoked, missing scope, order not found) exits.
while :; do
  RESP=$(curl -s https://hqclouds.com/api/v1/orders/$ORDER \
    -H "Authorization: Bearer $HQC_TOKEN")
  STATUS=$(echo "$RESP" | jq -r '.order.status // empty' 2>/dev/null)
  case "$STATUS" in registered|failed) break ;; esac
  CODE=$(echo "$RESP" | jq -r 'if .ok == false then .error.code else empty end' 2>/dev/null)
  case "$CODE" in ""|rate_limited|internal_error) sleep 60 ;; *) echo "$CODE" >&2; exit 1 ;; esac
done
[ "$STATUS" = "registered" ] || { echo "$DOMAIN: $STATUS" >&2; exit 1; }
# Platform test mode (sandbox): not a real domain — do not report a purchase to the user and do not list it.
[ "$(echo "$RESP" | jq -r '.order.registration.real')" = "true" ] || { echo "$DOMAIN: sandbox" >&2; exit 1; }

# 3. List by the order number: your price and an AI description right away. A retry returns the same listing (already_listed).
curl -s --max-time 60 -X POST https://hqclouds.com/api/v1/market/lots \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"order_id\":\"$ORDER\",\"price\":\"249\",\"describe\":\"ai\"}" | jq '.lot.card, .ai'

# 4. Edit: a new price and your own headline (seller text wins over AI; null brings back the automatic description).
curl -s -X PATCH https://hqclouds.com/api/v1/market/lots/$DOMAIN \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"price":"199","headline":"Short brandable .com"}' | jq '.lot.card'

# 5. Regenerate the AI description (force — even if one already exists).
curl -s --max-time 60 -X POST https://hqclouds.com/api/v1/market/lots/$DOMAIN/describe \
  -H "Authorization: Bearer $HQC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"force":true}' | jq '.ai'

# 6. Delist it if you change your mind.
curl -s -X DELETE https://hqclouds.com/api/v1/market/lots/$DOMAIN \
  -H "Authorization: Bearer $HQC_TOKEN" | jq '.lot.raw_status'
  • The order number (dq_…) is the key to the whole path: GET /orders/{id} shows the purchase outcome, the domain and the next step, and POST /market/lots with order_id lists the domain without repeating its name. All orders — GET /orders.
  • Every step is safe to repeat: the purchase with the same Idempotency-Key (the script prints KEY: run it again with KEY=… and it continues the same purchase instead of starting a new one), listing returns the same listing with already_listed: true, describe without force returns the existing text, and a repeated delisting returns the already delisted listing.
  • A freshly bought domain is paid for a year, so the “paid for at least 30 more days” rule is met immediately.
  • describe: "ai" waits for the model: usually 5–30 seconds, at most ~45 seconds (the script uses --max-time 60). If AI is unavailable or hits a limit, the listing is still created — ai has status: failed with a code, and buyers see the automatic description. Without describe, the AI description appears by itself within a few minutes if it is enabled on the platform.
  • Buying needs a key with the domains:register scope, listing — with market:write. One key can have both.

FAQ

How much does the API cost?

The API is free. Domains bought via the API cost the same as on the website; the money is charged to your HQClouds balance.

What if a purchase request times out?

Ask how the purchase ended: GET /api/v1/domains/register/{Idempotency-Key} — it buys and charges nothing. If the order exists, the response has its status and number; “not started” (404 not_started) — repeat the POST with the same Idempotency-Key. Repeating the POST with the same key is always safe: if the purchase already went through, the API returns its result and does not charge you twice.

Can I buy a premium domain via the API?

No. A premium domain can cost hundreds of times more than a regular one, so such domains can only be bought manually in the dashboard.

How do I list a domain for sale right after buying it?

The purchase response contains the order number order.id. Wait for status: registered in GET /api/v1/orders/{id} and send POST /api/v1/market/lots with order_id — the price, category and description are optional; request an AI description with describe: "ai".

How do I revoke a token?

In the dashboard, in the “API” section: revocation takes effect immediately. Create a new key and replace the token in your software.

Ready to start?

Create a key in the dashboard — it is free and takes a minute.