API

JSON · limits by plan

Overview

There are no API keys. Whether anonymous callers are allowed is up to the operator: when sign-in is required, every route answers 401 login_required without a signed-in browser session.

MethodPathReturns
GET/api/check?domain=One name: status, name traits, registry details, our crawl listing
POST/api/check/bulkUp to 25 names: status and name traits
GET/api/footprint?name=The same label on .com .ai .io .net .org .co .app (DNS only)
GET/api/marketRegistry counters, daily registrations, registered domains per month
GET/api/directoryWebsites on .si domains from our crawl, including for-sale landers
GET/api/wordsDictionary words and short codes with their DNS state in the .si zone, as JSON or CSV
GET/api/statsDirectory counts per state and for-sale total
GET/api/public/namesNames listed for sale, any extension (open to everyone)
POST/api/demandDemand signal for one name (signed in)

Check one name

domain may be kopi, kopi.si or a URL. Subdomains and protocols are stripped, and IDN names are converted to punycode. A bare name means .si. Other extensions work too (kopi.com, kopi.co.id): DNS is asked first, then that extension's own registry over RDAP, found through IANA's bootstrap file. Where an extension publishes no RDAP service, only DNS can speak and an unregistered answer stays unknown. Any extension in the Public Suffix List works, including second-level ones such as kopi.co.uk and kopi.com.ua; subdomains are cut to the registrable name, and special-use or unknown extensions (.local, .test) are refused. Reserved labels and the listing from our crawl exist for .si only.

curl "https://HOST/api/check?domain=cosmic"

Shape of a response; the values are illustrative.

{
  "domain": "cosmic.si",
  "tld": "si",
  "status": "registered",
  "via": "rdap",
  "checkedAt": 1790000000000,
  "details": {
    "registeredAt": "2025-09-17",
    "expiresAt": "2027-09-17",
    "lastChanged": "2026-06-10",
    "nameservers": ["ns1.afternic.com", "ns2.afternic.com"],
    "statusCodes": ["active"]
  },
  "forSale": { "platform": "Afternic", "via": "nameservers" },
  "traits": { "length": 6, "pattern": "LLLLLL", "tags": ["6L", "Dictionary"] },
  "listing": { "state": "parked", "salePlatform": "Afternic", "title": null }
}
statusavailable (registry answered 404), registered, reserved (112, 113, si, rs), or unknown (registry did not answer, see note)
viaHow the answer was reached. rules: a reserved label. dns: the zone has nameservers for it, so it is registered and the registry was not asked (also the fallback when the registry does not answer). cache: a recent "available" answer for a name without nameservers (kept 2 minutes). rdap: the registry answered live.
detailsDates exactly as the registry reports them (currently YYYY-MM-DD). Only on a single lookup of a registered name, and only when the registry answered (then via is rdap). Read live from RDAP, never stored. Estimate the release date as expiresAt plus 30 days.
forSalePresent when the nameservers belong to a marketplace lander: platform (Afternic, Sedo, Dan, Spaceship, Atom, ...) and via, always nameservers. Absent otherwise.
traitspattern uses L letter, N digit, H hyphen. Tags: 2L to 6L (letters only), <n>N (digits only, e.g. 3N), Letters+digits, Hyphen, Dictionary, Pronounceable, IDN. For IDN names length counts characters, not the punycode form.
listingWhat our crawl saw on the site: state, salePlatform (the marketplace of a for-sale lander, or null) and title. The whole value is null when we have not visited the name. Single lookups only.

Bulk check

At most 25 names per request, answers in input order inside {"results": [...]}. Duplicates are looked up once and every input still gets an answer. Invalid names return status: "invalid" with a reason. Entries carry traits and forSale but never details or listing: registry details are only given for a single lookup. A bare name or .si is checked as before: DNS, then the .si registry for a name without nameservers. Any other extension (kopi.com, kopi.co.id) is checked by DNS only and never reaches a registry: via is dns, a name with nameservers is registered, and a name without is unknown with candidate: true and a note. That is a candidate, not proof; look the name up on its own with /api/check.

curl -X POST https://HOST/api/check/bulk \
  -H 'content-type: application/json' \
  -d '{"domains":["cosmic","synapse.si","ko--pi"]}'
{ "results": [
  { "domain": "cosmic.si", "status": "registered", "via": "dns", "checkedAt": 1790000000000,
    "traits": { "length": 6, "pattern": "LLLLLL", "tags": ["6L", "Dictionary"] } },
  { "domain": "synapse.si", "status": "registered", "via": "dns", "checkedAt": 1790000000000,
    "traits": { "length": 7, "pattern": "LLLLLLL", "tags": ["Dictionary"] } },
  { "domain": "ko--pi", "status": "invalid",
    "reason": "A double hyphen in positions 3 and 4 is only valid for IDN names (xn--)." }
] }

Footprint

GET /api/footprint?name=cosmic returns registered, free, unknown or reserved per extension. A bare name or kopi.si is compared across .com .net .org .ai .io .co .app. A name on another extension (name=kopi.com) is compared across the other six plus .si. reserved is a .si label the registry holds back. This is a DNS delegation check, not registry data: a registered name parked without nameservers shows as free.

Market

GET /api/market returns {"registry": {...}} with total, last24h, lastMonth (the registry's own "new domains in last month" counter), fetchedAt and three series of [label, number] pairs: daily (["2026-10-05", 21756], registrations per day), monthly (registrations per month) and counts (registered domains at the end of each month). A series is an empty array when the registry's page does not publish it at the moment, so do not assume any of them is filled. Sales data is not offered yet: public reports capture only part of real .si sales, so showing them would read as complete when it is not.

Directory

ParameterValue
qPartial match on domain or title
statelive parked blocked dead pending
saleany for every for-sale lander, or a marketplace such as Afternic, Sedo, Dan, Spaceship, Atom
tech, langTechnology name (WordPress) and language code (sl)
page, perPage, and rows per page (1 to 100, default 25)
curl "https://HOST/api/directory?sale=Afternic&per=50"

The response is {"rows": [...], "total", "page", "pages", "per", "facets"}; facets lists the technologies, languages and marketplaces present, with counts. Rows carry domain, state, salePlatform, title, description, lang, tech[], https, tlsOk, hasMx, server, responseMs, crawledAt. Parked and for-sale detection is heuristic and can miss.

Words

GET /api/words lists one-word .si names from a large dictionary plus two and three character codes (the response says how many are indexed). Each name was looked up in the .si zone over DNS. dns is no-delegation (the zone has no nameservers for it), delegated or unscanned. No-delegation is a candidate, not proof of availability: registered names parked without nameservers look the same, especially common words. Confirm with /api/check before relying on a name.

ParameterValue
statusno-ns (default) delegated unscanned all
typeword (default) short (LL, LLL, NN, NNN codes) all
tierRarity up to: 1 core, 2 common, 3 familiar, 4 uncommon, 5 rare. 6 (obscure) is only returned when unset
min, maxLength in characters
q, starts, endsContains, starts with, ends with (letters and digits)
forms=1Include plurals and -ed/-ing forms of a more common word (hidden by default, heuristic)
freed=1Only names that lost their nameservers in the last 7 days, confirmed on three servers
sortbest (rarity, then length) short az fresh
page, perPage, and rows per page (1 to 200, default 50)
format=csv, limitThe same filters as CSV. limit defaults to 1,000 rows; the cap is your plan's (Free 1,000, Pro 25,000). Counts as 20 requests.
curl "https://HOST/api/words?type=word&tier=3&min=5&max=8&per=100"
curl -o words.csv "https://HOST/api/words?status=no-ns&format=csv&limit=25000"

The response is {"total", "page", "pages", "per", "coverage", "results": [...]}. coverage (indexed, scanned, lastScanAt) tells you how fresh the list is. Rows carry domain, length, rarity, type, inflection, dns, checkedAt and freedAt.

Public names

GET /api/public/names?q=&tld=&page=1&per=25 returns the names listed for sale, any extension, short names first. q is at most 80 characters, tld is like com or co.id, page is 1 to 100000 and per is 1 to 100. Each name has domain, unicode, label, tld, length, pattern, tags, ask ({minor, currency, display} or null), actions (which of buy, offer and contact exist) and urls.sheet and urls.lander. The response also has total, page, pages, per and tlds. Open to everyone and rate limited per address; a bad parameter answers 400 invalid_param. The pages are /names, /names/NAME and /forsale/NAME. Only names their owner listed appear; everything else answers 404. unicode is null unless the Unicode form is safe to show (one known script, no lookalike letters). The public pages allow 240 views a minute per address, then 429 with Retry-After.

Demand

curl -X POST https://HOST/api/demand -H 'content-type: application/json' -d '{"domain":"kopi.com"}'

POST /api/demand estimates, from public web signals, whether companies already use a name as a brand or product. Any extension; a bare name means .si. Signed-in sessions only, because every fresh check sends paid web searches (up to 4). Returns { id, domain, cached, checkedAt, quota, result }. result.verdict is strong, moderate or weak; result.evidence[] lists the sites that use the name (name, host, title, url, score 1 to 10, reasons[]); result.summary[] explains the verdict. A name checked in the last 24 hours returns the stored result at no cost (cached: true). A check counts against your allowance when at least one of its searches was answered, even if the check then fails (the answer carries charged: true); a check that fails before any search is answered does not count. Limits: per plan per UTC day and per minute, no single account above 25% of the service ceiling, and a service-wide ceiling. Errors: 401 login_required, 400 invalid_domain or invalid_param, 413, 415, 429 minute_limit, daily_limit or failure_limit (with Retry-After), 503 not_configured, paused (also what members see when search credit is spent) or service_limit, 502 and 504 provider_failed. No people, emails or contacts are ever returned.GET /api/demand/ID returns a stored check to the account that ran it, and 404 to anyone else.

Errors and limits

Errors look like {"error": "code", "message": "explanation"}.

  • 400 invalid_domain, invalid_param (a filter value out of range, the message names it), bad_json (body is not JSON), bad_body (domains missing or not an array of strings), too_many (over 25 names)
  • 413 too_large: the request body is over the size limit.
  • 404 not_found: no such API route.
  • 503 registry_unavailable: /api/market cannot reach the registry's statistics page and holds nothing older. Retry-After is 60.
  • 401 login_required: the operator turned on required login. The API then accepts a signed-in browser session only (there are no API keys yet).
  • 429 rate_limited: the per-minute allowance of your plan is used up. Visitors 120 while billing is internal, Free 30, Pro 300, staff 600 (a bulk request counts once per name). Signed-in users are counted per account, everyone else per IP. Retry-After gives the wait in seconds. CSV exports are capped by plan too (Free 1,000 rows, Pro 25,000). Registry lookups are also limited per day: 500 for staff, 200 for Pro, 30 for Free and for visitors (per address), and each registry has its own daily ceiling for the whole service. Past a limit a check answers unknown with a note. /api/footprint costs 7 units of the per-minute allowance (8 for an extension outside the usual seven).
  • 500 internal: our side. The status cache is optional, so a broken cache never blocks a check.

Data sources

  • Availability: public DNS, then ARNES RDAP (https://rdap.register.si), only for names a user asked about.
  • Registry statistics: the counters and the daily registrations and domain count charts the registry publishes on register.si.
  • Directory: Common Crawl index plus our own crawler. No RDAP data inside.
  • Words: the SCOWL word lists and a large public dictionary, each word looked up in the zone by asking the .si nameservers directly over TCP. DNS only, no RDAP.

The ARNES RDAP terms forbid copying, extracting or publishing its database and using it for advertising or bulk messages. DNagent does not sweep RDAP and keeps only a short-lived availability status.

Crawler

User-Agent DNagentBot/0.1 (+contact). It visits each domain's homepage at most once per round, reads robots.txt first, refuses internal IP addresses and caps downloads at 300 KB. It stores metadata only: HTTP status, title, description, language, detected technologies, for-sale marketplace, nameserver, MX presence. Page content is not stored.

To opt out, add this to your robots.txt:

User-agent: DNagentBot
Disallow: /

Not available

  • Our own drop or expiry list, and a list of all registered .si names. The registry's terms forbid building them from RDAP, and its zone file is not public. The Words index only covers dictionary words and short codes, from DNS. See the Drops page for third-party lists.
  • Email alerts for the watchlist. They need an account.