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.
| Method | Path | Returns |
|---|---|---|
| GET | /api/check?domain= | One name: status, name traits, registry details, our crawl listing |
| POST | /api/check/bulk | Up 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/market | Registry counters, daily registrations, registered domains per month |
| GET | /api/directory | Websites on .si domains from our crawl, including for-sale landers |
| GET | /api/words | Dictionary words and short codes with their DNS state in the .si zone, as JSON or CSV |
| GET | /api/stats | Directory counts per state and for-sale total |
| GET | /api/public/names | Names listed for sale, any extension (open to everyone) |
| POST | /api/demand | Demand 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 }
}status | available (registry answered 404), registered, reserved (112, 113, si, rs), or unknown (registry did not answer, see note) |
via | How 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. |
details | Dates 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. |
forSale | Present when the nameservers belong to a marketplace lander: platform (Afternic, Sedo, Dan, Spaceship, Atom, ...) and via, always nameservers. Absent otherwise. |
traits | pattern 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. |
listing | What 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
| Parameter | Value |
|---|---|
q | Partial match on domain or title |
state | live parked blocked dead pending |
sale | any for every for-sale lander, or a marketplace such as Afternic, Sedo, Dan, Spaceship, Atom |
tech, lang | Technology name (WordPress) and language code (sl) |
page, per | Page, 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.
| Parameter | Value |
|---|---|
status | no-ns (default) delegated unscanned all |
type | word (default) short (LL, LLL, NN, NNN codes) all |
tier | Rarity up to: 1 core, 2 common, 3 familiar, 4 uncommon, 5 rare. 6 (obscure) is only returned when unset |
min, max | Length in characters |
q, starts, ends | Contains, starts with, ends with (letters and digits) |
forms=1 | Include plurals and -ed/-ing forms of a more common word (hidden by default, heuristic) |
freed=1 | Only names that lost their nameservers in the last 7 days, confirmed on three servers |
sort | best (rarity, then length) short az fresh |
page, per | Page, and rows per page (1 to 200, default 50) |
format=csv, limit | The 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"}.
400invalid_domain,invalid_param(a filter value out of range, the message names it),bad_json(body is not JSON),bad_body(domainsmissing or not an array of strings),too_many(over 25 names)413too_large: the request body is over the size limit.404not_found: no such API route.503registry_unavailable:/api/marketcannot reach the registry's statistics page and holds nothing older.Retry-Afteris 60.401login_required: the operator turned on required login. The API then accepts a signed-in browser session only (there are no API keys yet).429rate_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-Aftergives 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 answersunknownwith a note./api/footprintcosts 7 units of the per-minute allowance (8 for an extension outside the usual seven).500internal: 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.