Introduction
The CatchDoms API gives you programmatic access to 370,000+ expired and auction domains from Dynadot, GoDaddy, DropCatch, Catched, and ukbackorder.
All responses are JSON. The base URL for all endpoints is:
Data is refreshed daily. Auction bids update several times per day.
Authentication
All API requests require a Bearer token in the Authorization header.
To get your API key:
- Sign up or log in at catchdoms.com
- Go to the API Access page
- Create a new API token
API access requires a Pro subscription (468 EUR/year).
Example request header
Rate Limiting
The API is limited to 100 requests per minute per token.
Rate limit information is included in the response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Your rate limit per minute |
X-RateLimit-Remaining |
Requests remaining in current window |
If you exceed the rate limit, you will receive a 429 Too Many Requests response. Wait 60 seconds before retrying.
Use per_page=100 to fetch more results per request and reduce API calls.
Endpoints
/api/domains
List domains
Returns a paginated list of domains. Accepts query parameters for filtering.
/api/domains/{id}
Get single domain
Returns the full domain object by its numeric ID.
/api/user
Get authenticated user
Returns the currently authenticated user's information.
Query Parameters
All parameters are optional. Add them to the query string of GET /api/domains.
| Parameter | Type | Default | Description |
|---|---|---|---|
source |
string | — | Filter by source platformdynadot, catched, dropcatch, godaddy, ukdroplists |
tld |
string | — | Filter by TLD, with or without dot prefix.com or com |
score_min |
integer | — | Minimum quality score (0-100). 50+ for good domains, 70+ for excellent. |
age_min |
integer | — | Minimum age in years, based on Wayback first snapshot |
type |
string | — | Filter by domain typeauction, closeout, backorder |
has_bids |
boolean | — | Only domains with active auction bids |
has_backlinks |
boolean | — | Only domains with referring domains (SEO value) |
has_gmb |
boolean | — | Only domains with a Google My Business listing |
da_min |
integer | — | Minimum Domain Authority (0-100) |
rd_min |
integer | — | Minimum number of referring domains |
language |
string | — | Filter by detected language codeEN, FR, DE, ES, etc. |
contains |
string | — | Keyword the domain name must contain (max 50 chars) |
per_page |
integer | 50 | Results per page (1-100) |
page |
integer | 1 | Page number for pagination |
Response Fields
Each domain in the data array contains these fields.
| Field | Type | Nullable | Description |
|---|---|---|---|
| Identity | |||
id |
integer | No | Unique domain identifier |
name |
string | No | Full domain name |
tld |
string | No | Top-level domain with dot prefix |
source |
string | No | Source platform (dynadot, catched, dropcatch, godaddy, ukdroplists) |
type |
string | No | Domain type (auction, closeout, backorder) |
auction_type |
string | Yes | Sub-type for DropCatch (Dropped, PreRelease, PrivateSeller) or GoDaddy (Bid, BuyNow) |
| Pricing | |||
price |
float | Yes | Fixed price for closeouts, or starting price for auctions |
max_bid |
float | Yes | Current highest bid for auction domains |
effective_price |
float | Yes | The actual price to pay: max_bid if set, otherwise price. Use this field instead of checking both price and max_bid. |
bids_count |
integer | Yes | Number of bids placed on the domain |
auction_end_date |
string (ISO 8601) | Yes | When the auction ends (ISO 8601) |
| Scoring | |||
estibot_appraisal |
float | Yes | Automated valuation estimate from the registrar |
score |
integer | Yes | CatchDoms quality score (0-100), combining age, authority, backlinks, name quality, and TLD |
is_spammy |
boolean | No | Whether the domain was flagged as spammy |
| History | |||
age |
integer | Yes | Domain age in years (computed from wayback_first_date) |
wayback_snapshots |
integer | Yes | Total number of Wayback Machine snapshots |
wayback_first_date |
string (YYYY-MM-DD) | Yes | Date of earliest Wayback snapshot (YYYY-MM-DD) |
wayback_last_date |
string (YYYY-MM-DD) | Yes | Date of latest Wayback snapshot (YYYY-MM-DD) |
| SEO Metrics | |||
pagerank |
integer | Yes | Open PageRank score (0-10) |
domain_authority |
integer | Yes | Domain Authority from DataForSEO (0-100) |
backlinks_count |
integer | Yes | Total number of backlinks |
referring_domains |
integer | Yes | Number of unique referring domains |
| Traffic | |||
monthly_visitors |
integer | Yes | Estimated monthly visitors (Dynadot domains only) |
| Language | |||
language |
string | Yes | Detected language code (EN, FR, DE, etc.), from Wayback archived content |
| Links | |||
purchase_url |
string | Yes | Direct link to bid/buy on the source platform |
| Timestamps | |||
created_at |
string (ISO 8601) | No | When the domain was added to CatchDoms (ISO 8601) |
updated_at |
string (ISO 8601) | No | When the domain was last updated (ISO 8601) |
effective_price — The actual price to pay: max_bid if set, otherwise price. Use this field instead of checking both price and max_bid.
Pagination
All list endpoints return paginated results using Laravel's standard pagination format.
The meta object contains:
current_page | Current page number |
last_page | Last page number |
per_page | Items per page |
total | Total matching domains |
from | First item index on this page |
to | Last item index on this page |
The links object contains:
first | URL to the first page |
last | URL to the last page |
prev | URL to the previous page (null on first page) |
next | URL to the next page (null on last page) |
{
"data": [ ... ],
"links": {
"first": "https://catchdoms.com/api/domains?page=1",
"last": "https://catchdoms.com/api/domains?page=68",
"prev": null,
"next": "https://catchdoms.com/api/domains?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 68,
"per_page": 50,
"to": 50,
"total": 3400
}
}
Code Examples
Replace YOUR_API_KEY with your actual token.
# List domains with score >= 50 and backlinks
curl "https://catchdoms.com/api/domains?score_min=50&has_backlinks=1&per_page=10" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
# Get a single domain by ID
curl "https://catchdoms.com/api/domains/12345" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
# Filter by TLD and language
curl "https://catchdoms.com/api/domains?tld=.fr&language=FR&age_min=10" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://catchdoms.com/api';
// List domains with filters
const params = new URLSearchParams({
score_min: 50,
has_backlinks: 1,
per_page: 10
});
const response = await fetch(`${BASE_URL}/domains?${params}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Accept': 'application/json'
}
});
const { data, meta } = await response.json();
console.log(`Found ${meta.total} domains`);
// Get a single domain
const domain = await fetch(`${BASE_URL}/domains/12345`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Accept': 'application/json'
}
}).then(r => r.json());
import requests
API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://catchdoms.com/api'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Accept': 'application/json'
}
# List domains with filters
response = requests.get(f'{BASE_URL}/domains', headers=headers, params={
'score_min': 50,
'has_backlinks': 1,
'language': 'FR',
'per_page': 25
})
data = response.json()
print(f"Found {data['meta']['total']} domains")
for domain in data['data']:
print(f"{domain['name']} - Score: {domain['score']} - Price: {domain['effective_price']}")
# Get a single domain
domain = requests.get(f'{BASE_URL}/domains/12345', headers=headers).json()
Errors
The API uses standard HTTP status codes. Error responses include a JSON body with a message field.
| Code | Meaning | Description |
|---|---|---|
| 200 | Success | Request completed successfully |
| 401 | Unauthorized | Missing or invalid API token |
| 403 | Forbidden | Valid token but no Pro subscription |
| 404 | Not Found | Domain ID does not exist |
| 422 | Validation Error | Invalid parameter value (e.g. score_min=abc) |
| 429 | Too Many Requests | Rate limit exceeded. Wait 60 seconds. |
Example error response
// 401 Unauthorized
{
"message": "Unauthenticated."
}
// 429 Too Many Requests
{
"message": "Too Many Attempts."
}
MCP Server
CatchDoms includes an MCP (Model Context Protocol) server for AI assistants like Claude Code, Cursor, and Windsurf.
Instead of writing API calls, you can ask natural language questions:
Configuration
Add this to your MCP client config:
{
"mcpServers": {
"catchdoms": {
"url": "https://catchdoms.com/mcp/catchdoms",
"transport": "sse",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
Claude Code: ~/.claude.json | Cursor: MCP settings
Learn more about MCP integration