Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Cheapest Domains public Tlds API
version: 1.13.0
description: Lowest standard prices among connected registrars with saved offers matching the query, including labeled samples and labeled registrar API rates; offers that couldn’t be refreshed for a day stay, with their age, until a newer catalog replaces them. Coverage is not the whole market. Public GET-only research access, no authentication. Exact-name availability has a separate provider-scoped endpoint. No purchase, renewal, transfer, or account operations. Query current prices instead of relying on remembered values.
servers:
- url: https://www.cheapest.domains
security: []
tags:
- name: Tlds
paths:
/api/v1/tlds/{tld}:
get:
operationId: get_tld_prices
summary: Compare prices for an extension
description: Compare all covered registrars for one extension. Returns source failures, quote timestamps and minimum terms; availability is not checked.
security: []
parameters:
- name: tld
in: path
required: true
description: One covered ASCII top-level extension, such as com or .com. Multi-part suffixes and IDNs are not covered.
schema:
type: string
pattern: ^\.?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$
maxLength: 64
description: One covered ASCII top-level extension, such as com or .com. Multi-part suffixes and IDNs are not covered.
- name: registrar
in: query
required: false
description: Connected registrar ID from the registrars endpoint. Omit to compare all.
schema:
type: string
maxLength: 40
pattern: ^[a-z0-9-]+$
description: Connected registrar ID from the registrars endpoint. Omit to compare all.
- name: registrars
in: query
required: false
description: Comma-separated connected registrar IDs to compare together. Use instead of registrar. Cheapest-per-extension winners are chosen within this set.
schema:
type: string
maxLength: 200
pattern: ^[a-z0-9-]+(?:,[a-z0-9-]+)*$
description: Comma-separated connected registrar IDs to compare together. Use instead of registrar. Cheapest-per-extension winners are chosen within this set.
- name: favorites
in: query
required: false
description: Up to two distinct connected registrar IDs, comma-separated. Adds saved favorite offers and fresh baselines for this result page, independent of filters. Does not save preferences or check names.
schema:
type: string
maxLength: 81
pattern: ^[a-z0-9-]+(?:,[a-z0-9-]+)?$
description: Up to two distinct connected registrar IDs, comma-separated. Adds saved favorite offers and fresh baselines for this result page, independent of filters. Does not save preferences or check names.
- name: sort
in: query
required: false
description: Ranking metric. Total uses a conservative new-registration estimate.
schema:
type: string
enum:
- renewal
- registration
- total
default: renewal
description: Ranking metric. Total uses a conservative new-registration estimate.
- name: orderBy
in: query
required: false
description: Order results by the selected price metric or extension. Cheapest-per-extension winners are selected before ordering.
schema:
type: string
enum:
- price
- extension
default: price
description: Order results by the selected price metric or extension. Cheapest-per-extension winners are selected before ordering.
- name: direction
in: query
required: false
description: Ascending or descending result order. Unknown totals follow priced totals in either price direction.
schema:
type: string
enum:
- asc
- desc
default: asc
description: Ascending or descending result order. Unknown totals follow priced totals in either price direction.
- name: years
in: query
required: false
description: Planning horizon in years, including initial registration.
schema:
type: integer
minimum: 1
maximum: 10
default: 3
description: Planning horizon in years, including initial registration.
- name: includeStale
in: query
required: false
description: Accepted for compatibility. Saved prices stay in results until a successful refresh replaces them and are labeled stale. includeStale=true still requires view=all.
schema:
type: boolean
default: false
description: Accepted for compatibility. Saved prices stay in results until a successful refresh replaces them and are labeled stale. includeStale=true still requires view=all.
- name: limit
in: query
required: false
description: Maximum number of results, up to 200.
schema:
type: integer
minimum: 1
maximum: 200
default: 50
description: Maximum number of results, up to 200.
- name: offset
in: query
required: false
description: Result offset. Follow pagination.next for additional results; the feed can change between requests.
schema:
type: integer
minimum: 0
maximum: 100000
default: 0
description: Result offset. Follow pagination.next for additional results; the feed can change between requests.
- name: name
in: query
required: false
description: One ASCII domain label without the extension, such as myproject. Price and link tools only build links from it; availability and popularity tools send the exact domain to their providers.
schema:
type: string
pattern: ^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$
maxLength: 63
description: One ASCII domain label without the extension, such as myproject. Price and link tools only build links from it; availability and popularity tools send the exact domain to their providers.
- name: format
in: query
required: false
description: Response representation. CSV and Markdown use the same filters, order and bounded pagination; they contain main offers, not favorite comparison arrays. MCP retains structured JSON alongside rendered text.
schema:
type: string
enum:
- json
- csv
- markdown
default: json
description: Response representation. CSV and Markdown use the same filters, order and bounded pagination; they contain main offers, not favorite comparison arrays. MCP retains structured JSON alongside rendered text.
responses:
'200':
description: Success. Inspect coverage, stale flags, minimum terms and pagination.
content:
application/json:
schema:
$ref: '#/components/schemas/Prices'
text/csv:
schema:
type: string
text/markdown:
schema:
type: string
'400':
description: Invalid, repeated, unknown, or incompatible parameters.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Endpoint, covered TLD, or connected registrar not found. Not a domain availability result.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'Request budget or concurrency limit reached. Anonymous calls spend weighted read units: 120 units/minute (burst 30) and 3,000/UTC day per network bucket, within a shared 600/minute (burst 120) and 30,000/UTC-day site-wide cap. Price searches rank the whole saved catalog and cost 10 units each; extension, registrar-coverage, estimate and registrar-link endpoints read one extension or source metadata and cost 1 unit, like other requests. Responses served from the CDN cache spend nothing. Each availability or popularity lookup spends 1 unit more plus one lookup from a separate allowance of 10 lookups/minute (burst 4), 300/UTC day and 3,000 per aligned 32-day window. Shared networks can share a bucket, and provider concurrency limits can also answer 429. Wait for the Retry-After seconds before retrying; do not poll.'
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: Fresh pricing unavailable. Retry after 60 seconds; inspect registrar coverage.
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Tlds
/api/v1/tlds/{tld}/history:
get:
operationId: get_price_history
summary: Get price history for an extension
description: 'Return how each covered registrar''s renewal or registration price for one extension changed over time: price periods with the date each price was first seen, when the previous price was last seen, and whether it came from our scheduled refreshes or the registrar''s own price page archived by the Internet Archive. A first record may be older than its date. Availability is not checked.'
security: []
parameters:
- name: tld
in: path
required: true
description: One covered ASCII top-level extension, such as com or .com. Multi-part suffixes and IDNs are not covered.
schema:
type: string
pattern: ^\.?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$
maxLength: 64
description: One covered ASCII top-level extension, such as com or .com. Multi-part suffixes and IDNs are not covered.
- name: registrar
in: query
required: false
description: Connected registrar ID from the registrars endpoint. Omit to compare all.
schema:
type: string
maxLength: 40
pattern: ^[a-z0-9-]+$
description: Connected registrar ID from the registrars endpoint. Omit to compare all.
- name: price
in: query
required: false
description: 'Which price history to return: the annual renewal (default) or the first-year registration, which includes promotions.'
schema:
type: string
enum:
- renewal
- registration
default: renewal
description: 'Which price history to return: the annual renewal (default) or the first-year registration, which includes promotions.'
- name: format
in: query
required: false
description: Response representation. CSV and Markdown use the same filters, order and bounded pagination; they contain main offers, not favorite comparison arrays. MCP retains structured JSON alongside rendered text.
schema:
type: string
enum:
- json
- csv
- markdown
default: json
description: Response representation. CSV and Markdown use the same filters, order and bounded pagination; they contain main offers, not favorite comparison arrays. MCP retains structured JSON alongside rendered text.
responses:
'200':
description: Success. Inspect coverage, stale flags, minimum terms and pagination.
content:
application/json:
schema:
$ref: '#/components/schemas/PriceHistory'
text/csv:
schema:
type: string
text/markdown:
schema:
type: string
'400':
description: Invalid, repeated, unknown, or incompatible parameters.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Endpoint, covered TLD, or connected registrar not found. Not a domain availability result.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'Request budget or concurrency limit reached. Anonymous calls spend weighted read units: 120 units/minute (burst 30) and 3,000/UTC day per network bucket, within a shared 600/minute (burst 120) and 30,000/UTC-day site-wide cap. Price searches rank the whole saved catalog and cost 10 units each; extension, registrar-coverage, estimate and registrar-link endpoints read one extension or source metadata and cost 1 unit, like other requests. Responses served from the CDN cache spend nothing. Each availability or popularity lookup spends 1 unit more plus one lookup from a separate allowance of 10 lookups/minute (burst 4), 300/UTC day and 3,000 per aligned 32-day window. Shared networks can share a bucket, and provider concurrency limits can also answer 429. Wait for the Retry-After seconds before retrying; do not poll.'
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'503':
description: Fresh pricing unavailable. Retry after 60 seconds; inspect registrar coverage.
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- Tlds
components:
schemas:
ServiceInformation:
type: object
required:
- name
- url
- setupUrl
- pluginUrl
description: Cheapest Domains identity and optional setup links, separate from upstream evidence. Does not establish client installation or provider health.
properties:
name:
const: Cheapest Domains
url:
type: string
format: uri
setupUrl:
type: string
format: uri
pluginUrl:
type: string
format: uri
Destination:
type: object
required:
- href
- mode
- domain
properties:
href:
type: string
format: uri
mode:
type: string
enum:
- search
- copy
- pricing
domain:
type: string
HistoryStep:
type: object
required:
- from
- to
- cents
- approximate
- source
- firstRecord
properties:
from:
type: string
format: date-time
description: When this price was first seen.
to:
type:
- string
- 'null'
format: date-time
description: When the next price or a removal was first seen; null while current.
cents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
regularCents:
type: integer
minimum: 0
description: Published regular price while this price is a promotion.
approximate:
type: boolean
description: Converted to USD from another currency.
source:
enum:
- refresh
- archive
description: 'refresh: our scheduled refresh (since 2026-09-28). archive: the registrar’s own price page as copied by the Internet Archive.'
changedAfter:
type: string
format: date-time
description: 'The previous price was last seen then: the change happened between this and from.'
firstRecord:
type: boolean
description: No earlier record; the price may be older than from.
lastConfirmed:
type: string
format: date-time
description: 'Archived prices: the last archived copy still showing this price.'
archiveUrl:
type: string
format: uri
Comparison:
type: object
required:
- url
- omittedParameters
description: Revisit current standard prices with supported website filters. Omits proposed names and API pagination; does not save prices or availability.
properties:
url:
type: string
format: uri
omittedParameters:
type: array
items:
enum:
- years
- favorites
description: Estimate horizons outside 2, 3, 5 and 10 years use the website default. Favorites are browser-local preferences and are never written by a link. Disclose omitted settings.
Coverage:
type: object
required:
- scope
- totalOffers
- freshOffers
- sources
- notCompared
- partial
properties:
scope:
type: string
totalOffers:
type: integer
freshOffers:
type: integer
partial:
type: boolean
error:
type:
- string
- 'null'
sources:
type: array
items:
$ref: '#/components/schemas/Source'
notCompared:
type: array
items:
type: object
properties:
name:
type: string
url:
type: string
reason:
type: string
Offer:
type: object
required:
- tld
- registrarId
- registrarName
- currency
- registrationCents
- renewalCents
- minimumTermYears
- stale
- estimatedTotalCents
- estimateYears
- availability
- pageUrl
- sourceUrl
- registrarSearch
properties:
tld:
type: string
registrarId:
type: string
registrarName:
type: string
currency:
const: USD
registrationCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
renewalCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
minimumTermYears:
type: integer
minimum: 1
countryCode:
type: boolean
sourceUrl:
type: string
format: uri
fetchedAt:
type:
- string
- 'null'
nextRefreshAt:
type:
- string
- 'null'
description: When the saved catalog is due for its next scheduled refresh; not an expiry of its prices.
stale:
type: boolean
description: True when the source’s last refresh failed and its saved catalog is at least 24 hours old. Passing nextRefreshAt alone does not make prices stale; a scheduled refresh every 15 minutes replaces due catalogs.
estimatedTotalCents:
type:
- integer
- 'null'
description: Null for multi-year minimum terms; not zero.
estimateYears:
type: integer
minimum: 1
maximum: 10
default: 3
description: Planning horizon in years, including initial registration.
availability:
const: not_checked
pageUrl:
type: string
format: uri
registrarSearch:
$ref: '#/components/schemas/Destination'
futureRenewalCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
futureRenewalDate:
type: string
regularRenewalCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
regularRegistrationCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
transferCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
registrationTermCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
renewalTermCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
pricingBasis:
type: string
enum:
- sampled_standard
- sampled_api
description: 'Absent for published price lists. sampled_standard: standard-tier prices sampled from registrar search results (Cloudflare). sampled_api (API 1.9.0): registrar API purchase and auto-renewal rates sampled with a synthetic name (GoDaddy); the registrar website and manual renewals can charge more. Both have limited coverage and are not exact-name quotes. Preserve this distinction when displaying or reusing prices.'
originalCurrency:
type: string
originalRegistrationCents:
type: integer
originalRenewalCents:
type: integer
exchangeRate:
type: number
exchangeRateDate:
type: string
exchangeRateSourceUrl:
type: string
billingCountry:
type: string
taxExcluded:
type: boolean
priceValidUntil:
type: string
format: date-time
description: When a scheduled price change takes effect or the exchange rate behind a converted price expires; recheck after this time.
renewalSince:
type: string
format: date-time
description: 'API 1.12.0: when this renewal price (with its regular price) was first seen; unchanged since. Absent when not yet dated. See renewalSinceFirstRecord and the price history endpoint.'
renewalSinceFirstRecord:
type: boolean
description: True when renewalSince is our earliest record of this price, so the price may be older. Say "unchanged since at least" that date.
PriceHistory:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
required:
- comparison
- tld
- price
- pageUrl
- historyStart
- registrars
- truncated
- notes
properties:
comparison:
$ref: '#/components/schemas/Comparison'
tld:
type: string
price:
enum:
- renewal
- registration
pageUrl:
type: string
format: uri
historyStart:
type:
- string
- 'null'
format: date-time
truncated:
type: boolean
description: True when only the newest periods fit one response.
notes:
type: array
items:
type: string
registrars:
type: array
items:
type: object
required:
- registrarId
- registrarName
- pageUrl
- listedNow
- current
- changes
- lowestCents
- highestCents
- steps
properties:
registrarId:
type: string
registrarName:
type: string
pageUrl:
type: string
format: uri
listedNow:
type: boolean
current:
type:
- object
- 'null'
description: The current step, with the same fields as steps[]; null when the registrar does not list the extension now.
changes:
type: integer
minimum: 0
lowestCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
highestCents:
type: integer
minimum: 0
description: Integer USD cents; 1000 = USD 10.
steps:
type: array
items:
$ref: '#/components/schemas/HistoryStep'
pricingBasis:
type: string
enum:
- sampled_standard
- sampled_api
description: The current saved offer’s sample label, as on price offers; absent for published price lists. Preserve it when quoting the current price.
stale:
type: boolean
description: True when the source’s last refresh failed and its saved catalog is at least 24 hours old. Passing nextRefreshAt alone does not make prices stale; a scheduled refresh every 15 minutes replaces due catalogs.
fetchedAt:
type:
- string
- 'null'
description: When the current saved offer was retrieved.
Source:
type: object
required:
- id
- name
- url
- offerCount
- freshOfferCount
- stale
- refreshing
properties:
id:
type: string
name:
type: string
url:
type: string
format: uri
note:
type: string
offerCount:
type: integer
freshOfferCount:
type: integer
fetchedAt:
type:
- string
- 'null'
nextRefreshAt:
type:
- string
- 'null'
description: When the saved catalog is due for its next scheduled refresh; not an expiry of its prices.
stale:
type: boolean
description: True when the source’s last refresh failed and its saved catalog is at least 24 hours old. Passing nextRefreshAt alone does not make prices stale; a scheduled refresh every 15 minutes replaces due catalogs.
refreshing:
type: boolean
error:
type:
- string
- 'null'
refresh:
type: object
required:
- phase
- completed
- total
- startedAt
- resumeAt
description: Progress of a staged catalog refresh, when one exists. Saved prices remain usable meanwhile.
properties:
phase:
enum:
- queued
- running
- waiting
- paused
- complete
completed:
type: integer
minimum: 0
total:
type: integer
minimum: 0
startedAt:
type: integer
description: Unix time in milliseconds.
resumeAt:
type: integer
description: Unix time in milliseconds.
Error:
type: object
required:
- apiVersion
- error
properties:
apiVersion:
type: string
error:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
retryAfterSeconds:
type: number
minimum: 0
Envelope:
type: object
required:
- service
- apiVersion
- generatedAt
- currency
- coverage
- limits
properties:
service:
$ref: '#/components/schemas/ServiceInformation'
apiVersion:
type: string
generatedAt:
type: string
format: date-time
currency:
const: USD
availability:
const: not_checked
coverage:
$ref: '#/components/schemas/Coverage'
limits:
type: array
items:
type: string
Prices:
allOf:
- $ref: '#/components/schemas/Envelope'
- type: object
required:
- comparison
- offers
- query
- pagination
properties:
comparison:
$ref: '#/components/schemas/Comparison'
offers:
type: array
maxItems: 200
items:
$ref: '#/components/schemas/Offer'
favoriteOffers:
type: array
maxItems: 400
description: Only requested favorites for this page’s extensions, independent of filters. Missing offers are absent; stale offers remain labeled.
items:
allOf:
- $ref: '#/components/schemas/Offer'
- type: object
properties:
differenceFromCheapestCents:
type:
- integer
- 'null'
description: Selected metric minus the lowest fresh quote across all connected registrars. Null for stale/unpriced quotes or absent fresh baseline; never claim savings from stale data.
favoriteBaselines:
type: array
maxItems: 200
items:
$ref: '#/components/schemas/Offer'
description: Lowest fresh saved quote per returned extension for the selected metric, independent of filters. Omitted where no fresh priced baseline exists.
query:
type: object
pagination:
type: object
required:
- limit
- offset
- total
- next
properties:
limit:
type: integer
offset:
type: integer
total:
type: integer
next:
type:
- string
- 'null'
externalDocs:
description: Human and AI integration guide
url: https://www.cheapest.domains/developers