GET /v1/aftermarket/{domain}

Aftermarket

Learn more: Aftermarket API — marketing overview, live demo, and use cases.

Check if a domain is listed for sale on aftermarket marketplaces. Aggregates real-time data from multiple providers using a pluggable multi-source architecture.

Endpoint

GET https://api.robotdomainsearch.com/v1/aftermarket/{domain}

The domain is a path parameter (e.g., /v1/aftermarket/example.com).

Parameters

Parameter Type Default Description
sources string (all enabled) Comma-separated list of sources to query. Example: ?sources=sedo,dynadot
timeout int 5000 Per-source timeout in milliseconds. Range: 1–15000. Values above 15000 are capped to 15000.
currency string USD Preferred display currency (Sedo prices auto-convert EUR→USD).

Request

Basic — Check all sources

curl https://api.robotdomainsearch.com/v1/aftermarket/premium.com

Filter to specific source

curl "https://api.robotdomainsearch.com/v1/aftermarket/premium.com?sources=sedo"

Multiple sources with custom timeout

curl "https://api.robotdomainsearch.com/v1/aftermarket/premium.com?sources=sedo,dynadot&timeout=8000"

Response

{
  "domain": "example.com",
  "timestamp": "2026-02-14T12:00:00Z",
  "listed": true,
  "summary": {
    "totalSources": 2,
    "sourcesChecked": 2,
    "sourcesWithData": 2,
    "listedCount": 2,
    "lowestPrice": {
      "amount": 2500.00,
      "currency": "USD",
      "source": "dynadot",
      "saleType": "buyNow"
    },
    "hasAuction": false,
    "hasMakeOffer": false,
    "hasBackorder": false
  },
  "listings": [
    {
      "source": "sedo",
      "platform": "Sedo",
      "status": "listed",
      "saleType": "buyNow",
      "price": {
        "amount": 2700.00,
        "currency": "USD"
      },
      "makeOffer": false,
      "auction": false,
      "url": "https://sedo.com/search/details/?domain=example.com",
      "affiliateUrl": "https://sedo.com/search/details/?domain=example.com&campaignId=330835",
      "lastChecked": "2026-02-14T12:00:00Z",
      "responseMs": 450
    },
    {
      "source": "dynadot",
      "platform": "Dynadot Marketplace",
      "status": "listed",
      "saleType": "buyNow",
      "price": {
        "amount": 2500.00,
        "currency": "USD"
      },
      "makeOffer": false,
      "auction": false,
      "url": "https://www.dynadot.com/market/auction/example.com",
      "affiliateUrl": "https://www.dynadot.com/market/auction/example.com",
      "lastChecked": "2026-02-14T12:00:00Z",
      "responseMs": 320
    }
  ],
  "errors": [],
  "meta": {
    "totalMs": 455,
    "affiliateDisclosure": "Links may earn RobotDomainSearch a commission at no extra cost to you.",
    "cacheHit": false,
    "cacheTTL": 900
  }
}

Response Fields

Top-Level Fields

Field Type Description
domain string The queried domain name (lowercased)
timestamp ISO 8601 When the response was generated
listed boolean true if the domain is listed on any source
summary object Aggregated overview across all sources
listings array Per-source listing details
errors array Per-source errors (partial failures)
meta object Request metadata

Listing Object

Field Type Description
source string Provider identifier (sedo, dynadot)
platform string Human-readable name (Sedo, Dynadot Marketplace)
status enum listed, notListed, auction, backorder, error
saleType enum buyNow, makeOffer, auction, backorder
price object? { amount: number, currency: string } — null if make-offer only
makeOffer boolean Whether the seller accepts offers
auction boolean Whether the domain is in an active auction
auctionDetails object? Auction end time, bid count, reserve status (when applicable)
url string Direct link to the listing page
affiliateUrl string Affiliate/partner link (earns RobotDomainSearch commission)
lastChecked ISO 8601 When this source was queried
responseMs number Source response time in milliseconds

Summary Object

Field Type Description
totalSources number Total registered providers
sourcesChecked number Providers queried (including errored)
sourcesWithData number Providers that returned valid data
listedCount number How many sources have the domain listed
lowestPrice object? Cheapest listing: { amount, currency, source, saleType }
hasAuction boolean Any source has an active auction
hasMakeOffer boolean Any source accepts offers
hasBackorder boolean Any source supports backorder

Error Object

Field Type Description
source string Which provider errored
code string Error code (see below)
message string Human-readable error description
retryable boolean Whether the request can be retried

Meta Object

Field Type Description
totalMs number Total response time in milliseconds
affiliateDisclosure string Disclosure notice about affiliate links
cacheHit boolean Whether the response was served from cache
cacheTTL number Cache TTL in seconds for this response

Domain Not Listed

When a domain is not listed on any marketplace:

{
  "domain": "my-random-domain-12345.com",
  "listed": false,
  "summary": {
    "totalSources": 2,
    "sourcesChecked": 2,
    "sourcesWithData": 2,
    "listedCount": 0,
    "hasAuction": false,
    "hasMakeOffer": false,
    "hasBackorder": false
  },
  "listings": [
    {
      "source": "sedo",
      "platform": "Sedo",
      "status": "notListed",
      "lastChecked": "2026-02-14T12:00:00Z",
      "responseMs": 380
    },
    {
      "source": "dynadot",
      "platform": "Dynadot Marketplace",
      "status": "notListed",
      "lastChecked": "2026-02-14T12:00:00Z",
      "responseMs": 210
    }
  ],
  "errors": [],
  "meta": { "totalMs": 385, "cacheHit": false, "cacheTTL": 3600 }
}

Error Handling

Error Codes

Code Meaning Retryable
not_configured Source not registered or missing credentials No
timeout Source didn’t respond within the timeout Yes
rate_limited Source returned 429 Yes
auth_error Invalid credentials (401/403) No
unavailable General source failure Yes

Partial Failures

The endpoint is designed for graceful degradation. If one source fails, others still return data:

{
  "domain": "example.com",
  "listed": true,
  "listings": [
    { "source": "dynadot", "status": "listed", "...": "..." }
  ],
  "errors": [
    {
      "source": "sedo",
      "code": "timeout",
      "message": "sedo: request failed: context deadline exceeded",
      "retryable": true
    }
  ]
}

HTTP Status Codes

Status Condition
200 Success (including partial failures with some data)
400 Invalid domain format
405 Method not allowed (only GET supported)
501 All requested sources are not_configured
503 All sources failed with retryable errors / service not initialized

Requesting an Unknown Source

curl "https://api.robotdomainsearch.com/v1/aftermarket/example.com?sources=afternic"

Returns 501 with:

{
  "errors": [{
    "source": "afternic",
    "code": "not_configured",
    "message": "Source 'afternic' is not configured",
    "retryable": false
  }]
}

Caching

Responses are cached in-memory with variable TTLs based on listing status:

Listing Status Cache TTL
Listed with price 15 minutes
Listed (make offer) 30 minutes
Active auction 5 minutes
Not listed 1 hour
Error / no data 30 seconds
  • Cache key is based on domain + sorted source list
  • meta.cacheHit indicates whether the response was served from cache
  • meta.cacheTTL shows the TTL in seconds for the current response
  • LRU eviction at 10,000 entries max

Architecture: Pluggable Multi-Source Design

RobotDomainSearch’s aftermarket endpoint uses a fan-out architecture:

  1. All enabled providers are queried in parallel using Go’s errgroup
  2. Each provider has an independent per-source timeout
  3. Results are aggregated into a single response with per-source detail
  4. Partial failures are captured in errors[] — successful sources still return data
  5. New providers can be added by implementing the AftermarketClient interface (1 file + 1 registration line)

Current Providers (Phase 1)

Source Platform API Type Notes
sedo Sedo SOAP/XML EUR→USD auto-conversion; requires partner ID + sign key
dynadot Dynadot Marketplace REST/JSON get_listing_item command; requires API key

Coming Soon

Additional providers planned for future releases:

  • Afternic (GoDaddy’s aftermarket network)
  • Dan.com
  • Atom.com (NameCheap)
  • Squadhelp

Domain Validation

  • Domains are lowercased and trimmed
  • Must match pattern: ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$
  • Max length: 253 characters
  • Invalid domains return 400 with invalid_domain error

Affiliate Disclosure

All responses include meta.affiliateDisclosure. Listing URLs may contain affiliate/partner parameters. The affiliateUrl field contains the affiliate link, while url is the direct listing link.

Code Examples

curl

curl https://api.robotdomainsearch.com/v1/aftermarket/premium.com

Python

import requests

response = requests.get(
    "https://api.robotdomainsearch.com/v1/aftermarket/premium.com"
)
data = response.json()

print(f"Domain: {data['domain']}")
print(f"Listed: {data['listed']}")

if data["listed"]:
    summary = data["summary"]
    print(f"Sources with listings: {summary['listedCount']}")
    if summary.get("lowestPrice"):
        lp = summary["lowestPrice"]
        print(f"Lowest price: ${lp['amount']:.2f} ({lp['source']})")

    for listing in data["listings"]:
        if listing["status"] == "listed":
            price = listing.get("price", {})
            print(
                f"  {listing['platform']}: ${price.get('amount', '?')} "
                f"({listing['saleType']})"
            )

for error in data.get("errors", []):
    print(f"  Error [{error['source']}]: {error['message']}")

JavaScript

const domain = "premium.com";
const response = await fetch(
  `https://api.robotdomainsearch.com/v1/aftermarket/${domain}`
);
const data = await response.json();

console.log(`Domain: ${data.domain}`);
console.log(`Listed: ${data.listed}`);

if (data.listed) {
  const { summary } = data;
  console.log(`Sources with listings: ${summary.listedCount}`);

  if (summary.lowestPrice) {
    const lp = summary.lowestPrice;
    console.log(`Lowest: $${lp.amount} (${lp.source})`);
  }

  data.listings
    .filter(l => l.status === "listed")
    .forEach(l => {
      console.log(`  ${l.platform}: $${l.price?.amount} (${l.saleType})`);
    });
}

data.errors?.forEach(e => {
  console.log(`  Error [${e.source}]: ${e.message}`);
});

Go

resp, err := http.Get("https://api.robotdomainsearch.com/v1/aftermarket/premium.com")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

var data struct {
    Domain  string `json:"domain"`
    Listed  bool   `json:"listed"`
    Summary struct {
        ListedCount int `json:"listedCount"`
        LowestPrice *struct {
            Amount   float64 `json:"amount"`
            Currency string  `json:"currency"`
            Source   string  `json:"source"`
        } `json:"lowestPrice,omitempty"`
    } `json:"summary"`
    Listings []struct {
        Source   string `json:"source"`
        Platform string `json:"platform"`
        Status   string `json:"status"`
        SaleType string `json:"saleType,omitempty"`
        Price    *struct {
            Amount   float64 `json:"amount"`
            Currency string  `json:"currency"`
        } `json:"price,omitempty"`
    } `json:"listings"`
    Errors []struct {
        Source  string `json:"source"`
        Code    string `json:"code"`
        Message string `json:"message"`
    } `json:"errors"`
}

if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
    log.Fatal(err)
}

fmt.Printf("Domain: %s (listed: %t)\n", data.Domain, data.Listed)
if data.Summary.LowestPrice != nil {
    fmt.Printf("Lowest: $%.2f (%s)\n",
        data.Summary.LowestPrice.Amount,
        data.Summary.LowestPrice.Source)
}
for _, l := range data.Listings {
    if l.Status == "listed" && l.Price != nil {
        fmt.Printf("  %s: $%.2f (%s)\n", l.Platform, l.Price.Amount, l.SaleType)
    }
}

Notes

  • The aftermarket endpoint requires the domain as a path parameter, not a query parameter
  • No API key is required during beta (60 requests/minute rate limit)
  • Sedo prices are returned in EUR and automatically converted to USD
  • The affiliateUrl earns RobotDomainSearch a commission at no extra cost to the buyer
  • Responses include both successful results and partial errors in a single response
  • Cache TTLs vary by listing status to balance freshness with performance