українські імена - значення, походження, відмінювання, історія

Ukrainian.name API

Read-only HTTP+JSON API over the Ukrainian.name names database — a deterministically-built, multilingual onomastic corpus (185,762 names; ~28K with substantive content; the rest are catalogued stubs).

changes only on a corpus rebuild — heavily cacheable on the client and at the edge)

and IPA are returned verbatim

This document is the source of truth. A plain-Markdown copy lives at 0 for AI agents and build pipelines; the human-readable version is at 1.


At a glance

#MethodPathReturns
1GET/v1/healthLiveness probe
2GET/v1/statsRow counts per entity table
3GET/v1/namesSearch/list names with facets
4GET/v1/names/{slug}Full record + entity graph for one name
5GET/v1/names/{slug}/relatedTyped relation neighbors
6GET/v1/tagsTags (categories/style) by usage
7GET/v1/tags/{label}/namesNames that carry a given tag

Pagination is offset/limit-based. Hard caps: limit ≤ 200 for name lists, limit ≤ 1000 for /v1/tags. Default limit = 50. Defaults to offset = 0.


1. GET /v1/health

Liveness probe. Returns 200 OK when the process is up and the SQLite spine is reachable in read-only mode.

Response 200

{ "ok": true }

2. GET /v1/stats

Row counts per entity table — useful for sanity checks, change detection, and dashboards.

Response 200

{
  "name": 185762,
  "name_relation": 240131,
  "tag": 318,
  "name_tag": 412980,
  "name_rating": 30214,
  "name_pronunciation": 18403,
  "name_nameday": 7211,
  "name_script": 24180,
  "name_reference": 9012,
  "name_usage": 211904,
  "name_popularity_region": 18002
}

Exact numbers vary between rebuilds; the keys are stable.


3. GET /v1/names

Search and list names with optional facet filters. All filters are AND-combined.

Query parameters

ParamTypeDefaultNotes
qstring""Case-insensitive substring against display_name; prefix against slug
genderenumf (feminine), m (masculine), u (unisex)
usagestringExact usage-language label (e.g. Ukrainian, English, Polish)
tagstringExact tag label (e.g. biblical, royal, flower-names)
limitint501 ≤ limit ≤ 200
offsetint0offset ≥ 0

Response 200

{
  "total": 1234,
  "limit": 50,
  "offset": 0,
  "names": [
    {
      "slug": "sofiia",
      "display_name": "Софія",
      "gender": "f",
      "summary": "From Greek Σοφία (Sophia) meaning \"wisdom\"…"
    }
  ]
}

endpoint 4.

Example

GET /v1/names?q=sof&gender=f&usage=Ukrainian&limit=20

4. GET /v1/names/{slug}

Full record for one name including the complete entity graph. The slug is the lowercase, official-Ukrainian transliterated form (KMU Resolution 55, 2010) — e.g. Софія → sofiia, Олександр → oleksandr. Slugs are URL-safe ASCII and stable.

Response 200

{
  "slug": "sofiia",
  "display_name": "Софія",
  "gender": "f",
  "usage": "Ukrainian, Russian, Bulgarian",
  "pronounced": "so-FEE-ya",
  "meaning": "Means \"wisdom\" in Greek (σοφία). …",
  "content_origin": "deterministic",
  "relations": [
    { "rel_type": "variant",        "dst_slug": "sophia",     "dst_name": "Sophia",     "dst_lang": "English" },
    { "rel_type": "diminutive",     "dst_slug": "sonia",      "dst_name": "Соня",       "dst_lang": "Ukrainian" },
    { "rel_type": "other_language", "dst_slug": "sofia-it",   "dst_name": "Sofia",      "dst_lang": "Italian"  }
  ],
  "tags": [
    { "label": "greek-origin",   "kind": "origin" },
    { "label": "biblical",       "kind": "category" }
  ],
  "ratings": [ "classic", "feminine", "wholesome" ],
  "pronunciations": [
    { "ipa": "soˈfija", "lang": "Ukrainian" }
  ],
  "namedays": [
    { "country": "Ukraine", "day": "09-17" }
  ],
  "scripts": [
    { "script": "Софія",  "lang": "Ukrainian" },
    { "script": "Σοφία",  "lang": "Greek"     }
  ],
  "references": [
    { "citation": "Hanks et al., Dictionary of First Names (2006)", "url": null }
  ],
  "usage": [
    { "usage_lang": "Ukrainian", "is_ancient": 0 },
    { "usage_lang": "Russian",   "is_ancient": 0 }
  ],
  "popularity_regions": [ "Ukraine", "Poland", "Bulgaria" ]
}

Response 404

{ "error": "name_not_found", "slug": "doesnotexist" }

Field reference

FieldTypeNotes
slugstringURL slug (lowercase, KMU 55 transliteration)
display_namestringNative form (Cyrillic for Ukrainian, etc.)
genderf\m\uu = unisex / unknown
usagestringComma-separated usage list, denormalised for display
pronouncedstring\nullHuman-readable pronunciation hint
meaningstring\nullLong-form etymology + history
content_originenumllm \deterministic \deterministic_low \template \stub — provenance of meaning
relations[]arrayTyped cross-references between names
tags[]arrayCurated tags (kindorigin, category, theme, style …)
ratings[]string[]Style descriptors ranked by community frequency (e.g. classic, wholesome)
pronunciations[]arrayIPA per language
namedays[]arrayCountry + MM-DD
scripts[]arrayNative scripts per language
references[]arrayCitation + optional URL
usage[]arrayPer-language usage with is_ancient flag
popularity_regions[]string[]Countries that track popularity for this name (absolute numbers deferred; see Roadmap)

content_origin values:

optional later enrichment pass (≈5.7K names)

(≈17.8K names)


5. GET /v1/names/{slug}/related

Typed relation neighbors of a single name — convenience over endpoint 4's relations[] field, with optional type filter.

Query parameters

ParamTypeNotes
typeenumFilter by rel_type. One of variant, diminutive, feminine, masculine, short_form, other_language, root, related

Response 200

{
  "slug": "sofiia",
  "related": [
    { "rel_type": "diminutive", "dst_slug": "sonia",  "dst_name": "Соня",  "dst_lang": "Ukrainian" },
    { "rel_type": "variant",    "dst_slug": "sophia", "dst_name": "Sophia","dst_lang": "English"  }
  ]
}

Response 200 (no matches)related: []. The slug itself is not validated by this endpoint; unknown slugs return an empty list rather than 404.


6. GET /v1/tags

List tags, ranked by the number of names carrying each tag (descending).

Query parameters

ParamTypeDefaultNotes
kindstringFilter to one kind: origin, category, theme, style, usage, nameday, …
limitint2001 ≤ limit ≤ 1000

Response 200

{
  "tags": [
    { "label": "biblical",      "kind": "category", "n": 4218 },
    { "label": "greek-origin",  "kind": "origin",   "n": 3104 },
    { "label": "flower-names",  "kind": "theme",    "n":  217 }
  ]
}

7. GET /v1/tags/{label}/names

Names that carry a given exact tag label. Pass the tag label exactly as returned by endpoint 6 (no fuzzy match).

Query parameters: limit (≤ 200, default 100), offset (default 0).

Response 200

{
  "tag": "biblical",
  "names": [
    { "slug": "adam",     "display_name": "Адам",     "gender": "m" },
    { "slug": "abraham",  "display_name": "Авраам",   "gender": "m" }
  ]
}

Order: display_name ascending. An unknown tag returns names: [].


Errors

All errors are JSON. The HTTP status is the primary signal; the body includes a stable, machine-readable error code plus a human hint.

StatuserrorWhen
404not_foundPath does not match any route
404name_not_foundslug does not exist in name
500internalUnexpected server fault. Body includes a truncated detail

Error body shape:

{ "error": "name_not_found", "slug": "doesnotexist" }

There are no 4xx validation errors today — out-of-range limit values are clamped (e.g. limit=10000 becomes 200), unknown enum values for gender and kind are ignored.


Rate limits & fair use

The API is intentionally cache-friendly: identical requests are deterministic, max-age=3600, and safe to cache aggressively at any layer. There are currently no per-key rate limits because there are no API keys. The hosting layer enforces edge-level abuse protection; heavy automated consumers should:

(Cloudflare adds these automatically; the Python reference server does not).

If you need bulk access, prefer the periodic JSON dump (see Bulk download below) rather than crawling the API.


Bulk download

A full JSON snapshot of every public name record will be published as a single gzipped file at:

Each name record in the JSONL file has the same shape as GET /v1/names/{slug}. The dump is rebuilt on every corpus build (deterministic; the file's ETag changes only when the corpus changes). For AI training/embedding pipelines, prefer the dump over per-name fetches — same content, fewer round-trips, kinder to the edge cache.

Status: the dump endpoints are part of the v1 contract and are rolled out in the first deployment of api.ukrainian.name.

Versioning

without a version bump. Clients MUST ignore unknown fields.

semantics) ship under a new prefix (/v2/). Both versions run side by side for at least 6 months.

considered part of the contract.


Data provenance

Every field is parsed deterministically from the public source crawl or generated by a deterministic transform on top of it (RULE 2: think holistically — don't LLM what is really ETL). The corpus is rebuilt by an idempotent pipeline; rebuilds change values only when the source text changes.

A small subset (~1.7K names) carries content_origin: "llm" — long-form prose rewrites cached from a one-off Claude pass. These are preserved across rebuilds and never overwritten by deterministic transforms.


Roadmap (intentional gaps)

These fields/endpoints are reserved in the data model but intentionally empty in v1; they ship once the deferred full-source crawl lands:

ships in v1, not the numbers)

When these populate, additive fields will appear on GET /v1/names/{slug}; no breaking change.


Reference: SDKs and quick recipes

curl

curl -s https://api.ukrainian.name/v1/names/sofiia | jq .
curl -s "https://api.ukrainian.name/v1/names?q=sof&gender=f&limit=10" | jq .
curl -sI https://api.ukrainian.name/v1/health

Python (stdlib, no deps)

import json, urllib.request
def get(path):
    with urllib.request.urlopen(f"https://api.ukrainian.name{path}") as r:
        return json.load(r)
rec = get("/v1/names/sofiia")
print(rec["meaning"][:200])

JavaScript (browser / Node 18+)

const rec = await fetch("https://api.ukrainian.name/v1/names/sofiia")
  .then(r => r.json());
console.log(rec.meaning.slice(0, 200));

Common queries

/v1/names?gender=f&usage=Ukrainian&limit=200&offset=0

/v1/tags/biblical/names?limit=200

/v1/names/sofiia/related?type=diminutive

/v1/tags?kind=origin&limit=50


For AI agents

If you are an LLM-driven agent integrating this API:

  1. Prefer the bulk dump (/v1/dump/names.jsonl.gz) for training,

embedding, or whole-corpus reasoning. One request, one ETag, fewer edge cache misses.

  1. Resolve names through /v1/names before fetching, so the slug

you use is canonical. Don't guess slugs by transliterating yourself; the corpus uses official Ukrainian (KMU 55, 2010) transliteration and may have suffix disambiguators for cross-language collisions.

  1. Treat content_origin as your trust signal: llm is the most

readable, deterministic is the most faithful to source, stub means there is no body — handle the empty meaning gracefully.

  1. Cite the canonical page at https://ukrainian.name/{slug} when

surfacing a name to a user. The API exposes the slug; concatenate it onto the site origin.

  1. This document is mirrored as Markdown at

https://ukrainian.name/api/docs.md — drop it in your context for schema-grounded responses.

  1. /llms.txt at https://ukrainian.name/llms.txt is the

short-form site map for AI agents.


Contact

0


Markdown source: /api/docs.md · AI-friendly site map: /llms.txt