Quick start
The Thexyz Domain Intelligence API gives you programmatic access to confirmed-dropped domain data — the same feed that powers our expired domains page.
- Get an API key — purchase any plan on the API plans page. The free tier requires no credit card. Your key is shown in your client area as soon as the order is provisioned (usually within a few seconds).
- Send it as a bearer token on every request.
- Make your first call:
curl -H "Authorization: Bearer YOUR_KEY" \ "https://www.thexyz.com/domain-intel/api/v1/quota"
That's it. Every endpoint follows the same shape: GET request, bearer-token auth, JSON response.
Finding your API key
After purchase, your key appears in two places:
- Welcome email — sent automatically when your order is paid. Look for the API key line.
- Client area — log in, go to Services → My Services, click your API plan. The page shows the key, today's usage, and ready-to-paste curl examples.
Treat the key like a password — anyone with it can spend your daily quota. If it's exposed, use the Rotate API Key action in your client area (or contact support) to invalidate it and issue a new one.
Authentication
Every authenticated request needs the Authorization header:
Authorization: Bearer di_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
For testing only, you can also pass the key as a query parameter:
?key=di_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Query-string auth is intended for ad-hoc testing — production clients should use the header so the key never lands in proxy logs or browser history.
Endpoints
| Endpoint | Auth? | Counts toward quota? | Purpose |
|---|---|---|---|
GET /v1/health |
No | No | Heartbeat / uptime check |
GET /v1/sample?domain=X |
No | No | Public single-domain preview (for evaluation) |
GET /v1/quota |
Yes | Yes (1 call) | See your plan limit + today's usage |
GET /v1/domains |
Yes | Yes (1 call) | Filtered list, paginated |
GET /v1/domains/{name} |
Yes | Yes (1 call) | Lookup a single domain by name |
GET /v1/check?domain=X / ?domains=X,Y,Z |
Yes | Yes (1 call) | Live availability check (single or bulk, up to 30) |
GET /v1/whois/{name} |
Yes | Yes (1 call) | Structured WHOIS via RDAP — works on most gTLDs |
GET /v1/suggest?keyword=X |
Yes | Yes (1 call) | Keyword-based domain suggestions |
Base URL: https://www.thexyz.com/domain-intel/api/v1/
Filtering the dropped-domain feed
All filters are optional. Combine as many as you like — they're AND-ed together.
| Parameter | Example | Effect |
|---|---|---|
status |
dropped (default), all, CSV |
Restrict to confirmed-available domains (default), or open up to in-zone, redemption, etc. |
tld |
com,net,org |
One or more TLDs (CSV) |
min_da |
20 |
Minimum Moz Domain Authority |
min_pa |
15 |
Minimum Moz Page Authority |
min_tf |
20 |
Minimum Majestic Trust Flow |
min_cf |
20 |
Minimum Majestic Citation Flow |
min_backlinks |
500 |
Minimum total backlinks |
min_ref_domains |
50 |
Minimum referring domains |
min_years |
15 |
Domain has been captured on Wayback for at least N distinct years (proxy for "aged") |
first_year_before |
2010 |
Wayback first saw this domain before year N (alternate "aged" filter) |
min_alt_taken |
3 |
At least N alternate TLDs of the same SLD are already registered (demand signal) |
source_category |
premium |
Curated category from the source feed |
q |
tech |
Substring match against the domain name |
sort |
da |
One of: da, pa, tf, cf, backlinks, ref_domains, years, first_year, first_seen, drop_date |
limit |
50 (max 100) |
Rows per response |
offset |
100 (max 10000) |
Pagination offset |
Response shape
Every successful list/detail response returns a data field plus optional paging info:
{
"data": [
{
"domain": "example.com",
"tld": "com",
"status": "dropped",
"first_seen": "2026-04-12",
"drop_date": "2026-05-20",
"metrics": {
"da": 35,
"pa": 28,
"tf": 22,
"cf": 30,
"backlinks": 1240,
"ref_domains": 87
},
"wayback": {
"snapshots": 18,
"first_year": 2003,
"age_years": 23,
"checked_at": "2026-05-23T15:42:11Z"
},
"alt_tld": {
"taken": 4,
"total": 8
},
"source": {
"category": "word",
"note": "seekahost"
},
"rdap_checked_at": "2026-05-23T15:30:02Z"
}
],
"paging": {
"limit": 25,
"offset": 0,
"total": 1842,
"has_more": true
},
"filters_applied": { "min_da": "20", "min_years": "10" }
}
Null vs zero: If a metric is null, we haven't enriched that signal yet (most commonly Moz/Majestic for non-aged domains). 0 means we checked and the real value is zero.
Code examples
curl
# Single domain
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/domains/example.com"
# Confirmed-dropped .com domains, aged 15+ years, DA ≥ 20, sorted by DA
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/domains?tld=com&min_years=15&min_da=20&sort=da&limit=25"
# Today's usage
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/quota"
Python
import requests
API = "https://www.thexyz.com/domain-intel/api/v1"
HEADERS = {"Authorization": "Bearer YOUR_KEY"}
# Aged .net drops, sorted by Trust Flow
r = requests.get(f"{API}/domains", headers=HEADERS, params={
"tld": "net",
"min_years": 15,
"sort": "tf",
"limit": 50,
})
for d in r.json()["data"]:
age = d["wayback"]["age_years"] or "—"
da = d["metrics"]["da"] or 0
tf = d["metrics"]["tf"] or 0
print(f"{d['domain']:30} DA={da} TF={tf} age={age}y")
Node.js
const KEY = process.env.THEXYZ_API_KEY;
const API = 'https://www.thexyz.com/domain-intel/api/v1';
async function findAged() {
const url = `${API}/domains?tld=com&min_years=20&limit=25`;
const r = await fetch(url, {
headers: { Authorization: `Bearer ${KEY}` }
});
const { data } = await r.json();
data.forEach(d =>
console.log(`${d.domain} age=${d.wayback.age_years}y`));
}
findAged();
PHP
<?php
$key = getenv('THEXYZ_API_KEY');
$url = 'https://www.thexyz.com/domain-intel/api/v1/domains?tld=com&min_years=20&limit=25';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($ch);
$data = json_decode($body, true);
foreach ($data['data'] as $d) {
printf("%-30s DA=%d age=%dy\n",
$d['domain'], $d['metrics']['da'], $d['wayback']['age_years']);
}
Rate limits
Quotas reset daily at 00:00 UTC. Every authenticated response includes two headers so your client can self-throttle:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 994
On the Enterprise tier, both headers read unlimited.
If you exceed your daily limit, the API returns HTTP 429 Too Many Requests with a Retry-After header (seconds until 00:00 UTC). Failed requests don't count against your quota.
HTTP/1.1 429 Too Many Requests
Retry-After: 14387
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
{
"error": "Daily quota exceeded.",
"status": 429,
"daily_quota": 1000,
"resets_at": "2026-05-25T00:00:00Z"
}
Error handling
Errors are always JSON with a consistent shape:
{
"error": "Invalid API key.",
"status": 401
}
| Status | Meaning | What to do |
|---|---|---|
| 400 | Bad request (e.g. malformed domain) | Validate your input client-side first. |
| 401 | Missing/invalid API key | Check the Authorization header. Re-copy the key from your client area. |
| 403 | API key revoked or suspended | Reactivate in the client area, or contact support if billing is current. |
| 404 | Domain not in our catalog, or unknown endpoint | Check spelling. Single-domain lookups return 404 only if we've never seen the domain. |
| 405 | Wrong HTTP method | Use GET — everything is read-only. |
| 429 | Daily quota exceeded | Wait until 00:00 UTC, or upgrade your plan. |
| 500 | Server error | Rare — please report with the request URL and timestamp. |
Live availability — /v1/check
Real-time availability check across any TLDs we resell. Single domain or bulk (up to 30 per request). Each request counts as 1 quota unit regardless of batch size — bulk callers get a discount.
# Single domain
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/check?domain=example.com"
# Bulk (comma-separated, up to 30)
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/check?domains=a.com,b.net,c.org"
Response shape:
{
"data": {
"a.com": {
"available": false,
"status": "regthroughothers",
"classkey": "domcno"
},
"b.net": {
"available": true,
"status": "available",
"classkey": "dotnet"
}
}
}
classkey is our wholesale pricing-class identifier for that TLD — useful if you also want to look up the registration cost.
Structured WHOIS — /v1/whois/{name}
Public WHOIS lookup via RDAP (RFC 7480). Works on every gTLD that runs an RDAP server (so most: .com, .net, .org, .io, .co, .ai, .dev, etc.). ccTLDs that don't have RDAP yet return a structured error field instead of crashing.
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/whois/example.com"
Response shape (registered domain):
{
"data": {
"domain": "example.com",
"available": false,
"status": ["clientTransferProhibited", "serverDeleteProhibited"],
"registered": "1995-08-13",
"expires": "2027-08-12",
"updated": "2024-08-13",
"registrar": "MarkMonitor Inc.",
"registrar_iana_id": "292",
"name_servers": ["a.iana-servers.net", "b.iana-servers.net"],
"registrant": {
"organization": "ICANN",
"country": "US"
}
}
}
Response shape (available domain — RDAP returns 404 → we surface as available: true):
{
"data": {
"domain": "unregistered-12345.com",
"available": true,
"note": "No RDAP record found — domain appears to be available."
}
}
Registrant data is often redacted in modern WHOIS (GDPR, registrar privacy services). When that's the case we omit the registrant field entirely rather than return useless placeholder strings. If you need authoritative ownership data, file a ticket — registrars can release it with the registrant's consent.
Suggestions — /v1/suggest
Keyword-based domain suggestions. Pass a seed word + a list of TLDs to check, get back up to ~20 alternative SLDs across those TLDs with availability flags.
# Cloud-themed names across com/net/io
curl -H "Authorization: Bearer YOUR_KEY" \
"https://www.thexyz.com/domain-intel/api/v1/suggest?keyword=cloud&tld=com,net,io"
Response shape:
{
"data": [
{ "domain": "cloudhq.io", "available": true, "status": "available" },
{ "domain": "cloudvault.net", "available": true, "status": "available" },
{ "domain": "cloudbase.com", "available": false, "status": "regthroughothers" },
...
],
"keyword": "cloud",
"tlds": ["com", "net", "io"]
}
Parameters:
| Parameter | Default | Notes |
|---|---|---|
keyword (required) |
— | 1–30 characters; alphanumeric + hyphen + space |
tld |
(unset — all supported TLDs) | CSV; up to 10 TLDs. Omit for broader results. |
exact |
false |
If true, only return TLD swaps of the exact keyword (no SLD alternatives) |
ccTLD caveat: suggestions are only available for gTLDs plus .us and .co. Passing other ccTLDs in tld= (e.g. .de, .uk, .nl) silently returns no suggestions for those — that's a registry limit, not an API bug.
Common patterns
Domain registration flow
# 1. Suggest names around a theme
GET /v1/suggest?keyword=apex&tld=com,net,io
# 2. Confirm one is still available
GET /v1/check?domain=apexcloud.io
# 3. (Optional) inspect WHOIS to be sure
GET /v1/whois/apexcloud.io
# 4. Send the customer to your cart for registration
Find aged, high-DA drops in .com
GET /v1/domains?tld=com&min_da=25&min_years=15&sort=da&limit=50
Find recent drops (last 24 hours) regardless of metrics
GET /v1/domains?status=dropped&sort=drop_date&order=DESC&limit=100
(Pair this with paginated polling on a cron to build an "all fresh drops" stream.)
Find SLDs with high alt-TLD demand
GET /v1/domains?min_alt_taken=4&sort=alt_tld&limit=50
Substring search within available domains
GET /v1/domains?q=tech&min_da=10&limit=25
Paginate efficiently
Use limit=100 + offset stepping by 100. For result sets above 10,000 rows, narrow the filter rather than paginating further — offset is capped at 10,000.
Where the data comes from
- ICANN CZDS zone files — daily delta of every
.com(and other TLDs we're approved for). Source of the "left the zone" signal. - RDAP — confirms whether a domain is actually registerable right now (status
dropped). - Internet Archive Wayback — age / history signal (
wayback_first_year,wayback_snapshots). - Curated importers (SeekaHost, expired.ca, etc.) — Moz DA/PA, Majestic TF/CF, backlinks.
- Live DNS — alt-TLD presence for the SLD.
The full pipeline updates ~hourly during the day. The full .com zone diff runs once per day at 06:00 UTC, after ICANN publishes that day's snapshot.
Best practices
- Cache responses — drop-date data only changes once per day. There's no need to re-poll the same query more than every few hours.
- Use the
filters_appliedfield for debugging. It echoes back the filters we recognised, so you can spot typos in parameter names. - Honour the rate-limit headers. Self-throttle before you hit 429 — your IP stays fast and our infra stays friendly.
- Validate domain names client-side before single-domain lookups (
example.com, nothttps://www.example.com/). - Pin to
/v1/in your integration. Future major changes will live under/v2/; existingv1contracts won't break.
Need more capacity?
If you're regularly bumping into your daily quota, upgrade in your client area — the change is instant (no key rotation needed). If your use case needs higher than the Enterprise tier (bulk export, daily snapshot delivery, custom filters, SLA), email sales@thexyz.com and we'll build a custom plan.
Still stuck?
Open a ticket from your client area — include the exact request URL (redact the key) and the response body. We'll get back to you within one business day on free/starter plans, faster on Pro and Enterprise.