Resolve a name to an id
Going from "NAVI" to a UUID — or skipping the lookup entirely.
You rarely start with a UUID. You start with a name.
Skip the lookup
Teams, players and tournaments accept a slug wherever a path id is expected, so if you know the slug you don't need a lookup at all:
curl -H "Authorization: Bearer $ESPORTSODDS_API_KEY" \
"https://api.esportsodds.gg/v1/cs2/teams/natus-vincere"
curl -H "Authorization: Bearer $ESPORTSODDS_API_KEY" \
"https://api.esportsodds.gg/v1/cs2/teams/natus-vincere/h2h?opponent=faze"Sub-resources and the ?opponent= parameter accept slugs too. Matches have no slug — a match id
is always a UUID.
When you have a display name, not a slug
Filter the list by slug and cache the result:
import functools
@functools.lru_cache(maxsize=512)
def team_id(slug: str) -> str | None:
rows = get(f"/v1/cs2/teams?slug={slug}")["data"]
return rows[0]["id"] if rows else None?slug= returns the single matching row — or an empty page — in the normal list envelope, and never
depends on paging position.
Cache aggressively: teams and players change far more slowly than anything else in the API, and a cached id costs you nothing.
Building a slug from a name
Slugs are lowercase and hyphenated, but not always a mechanical transform of the display name
(Natus Vincere → natus-vincere, but FaZe → faze). Guessing works often enough to be
dangerous and fails silently, returning an empty page.
If you're matching user input, walk the list once and build your own index:
index = {}
for team in paginate("/v1/cs2/teams", limit=500):
index[team["name"].lower()] = team["id"]
index[team["slug"]] = team["id"]
if team["short_name"]:
index.setdefault(team["short_name"].lower(), team["id"])At limit=500 that's a handful of requests for the whole roster, refreshable weekly.
Store the UUID, display the slug
Slugs are stable but not guaranteed permanent — an organisation rename can change one. For anything you persist, store the UUID and treat the slug as a display convenience. A UUID never changes.