API Reference

This section contains the full API reference for all public classes and functions.

Client

Vairified SDK Client — async-first, sub-resource organized.

Usage:

async with Vairified(api_key="vair_pk_xxx") as client:
    # Get a connected member
    member = await client.members.get("vair_mem_xxx")
    print(member.display_name, member.rating_for("pickleball"))

    # Auto-paginate a search
    async for member in client.members.search(city="Austin", rating_min=4.0):
        print(member.display_name)

    # Submit a bulk match batch
    result = await client.matches.submit(
        MatchBatch(
            sport="pickleball",
            win_score=11,
            win_by=2,
            bracket="4.0 Doubles",
            event="Weekly League",
            match_date="2026-04-11T14:00:00Z",
            matches=[
                Match(
                    identifier="m1",
                    teams=[["p1", "p2"], ["p3", "p4"]],
                    games=[Game(scores=[11, 8]), Game(scores=[11, 5])],
                ),
            ],
        )
    )
    print(f"Submitted {result.num_games} games")

Sub-resources:

  • Vairified.members — get/search/get_bulk/rating_updates

  • Vairified.matches — submit batch, tournament_import

  • Vairified.oauth — OAuth authorization flow

  • Vairified.leaderboard — leaderboard queries

  • Vairified.webhooks — webhook delivery inspection

  • Vairified.usage — API usage stats (method: await client.usage())

class vairified.client.LeaderboardResource[source]

Bases: _Resource

Read-only leaderboard queries.

Parameters:

client (Vairified)

async list(*, category=None, age_bracket=None, scope=None, state=None, city=None, club_id=None, gender=None, verified_only=False, min_games=None, limit=50, offset=0, search=None)[source]

Fetch a leaderboard page with optional filters.

Parameters:
  • category (str | None (default: None))

  • age_bracket (str | None (default: None))

  • scope (str | None (default: None))

  • state (str | None (default: None))

  • city (str | None (default: None))

  • club_id (str | None (default: None))

  • gender (str | None (default: None))

  • verified_only (bool (default: False))

  • min_games (int | None (default: None))

  • limit (int (default: 50))

  • offset (int (default: 0))

  • search (str | None (default: None))

Return type:

dict[str, Any]

async rank(player_id, *, category='doubles', age_bracket='open', scope='global', state=None, city=None, club_id=None, context_size=5)[source]

Fetch a specific player’s rank + nearby players.

Parameters:
  • player_id (str)

  • category (str (default: 'doubles'))

  • age_bracket (str (default: 'open'))

  • scope (str (default: 'global'))

  • state (str | None (default: None))

  • city (str | None (default: None))

  • club_id (str | None (default: None))

  • context_size (int (default: 5))

Return type:

dict[str, Any]

async categories()[source]

List available leaderboard categories, brackets, and scopes.

Return type:

dict[str, Any]

class vairified.client.MatchesResource[source]

Bases: _Resource

Match submission — one call submits a full batch.

Parameters:

client (Vairified)

async submit(batch)[source]

Submit a MatchBatch for rating calculation.

All players in every match must have granted the user:match:submit scope via OAuth (unless your API key has the user:match:submit:trusted scope, which skips per-player consent).

Set batch.dry_run = True to validate without persisting.

Example:

batch = MatchBatch(
    sport="pickleball",
    win_score=11,
    win_by=2,
    bracket="4.0 Doubles",
    event="Weekly League",
    match_date="2026-04-11T14:00:00Z",
    matches=[
        Match(
            identifier="m1",
            teams=[["vair_mem_aaa", "vair_mem_bbb"],
                   ["vair_mem_ccc", "vair_mem_ddd"]],
            games=[Game(scores=[11, 8]), Game(scores=[11, 5])],
        ),
    ],
)
result = await client.matches.submit(batch)
if result.ok:
    print(f"Submitted {result.num_games} games")
Parameters:

batch (MatchBatch)

Return type:

MatchBatchResult

async tournament_import(body)[source]

Import tournament results with automatic player matching.

Players are matched by email first, then name+location. Unmatched players become ghost accounts that can be claimed later.

Parameters:

body (dict[str, Any]) – Tournament data dict with keys: tournamentName, sport, winScore, winBy, matches (list of match dicts with identifier, event, bracket, format, matchDate, teamA, teamB).

Return type:

TournamentImportResult

Returns:

TournamentImportResult with counts.

Raises:

ValidationError – If the payload is malformed.

Example:

result = await client.matches.tournament_import({
    "tournamentName": "Austin Open 2026",
    "sport": "pickleball",
    "winScore": 11,
    "winBy": 2,
    "matches": [...]
})
print(f"Imported {result.matches_imported} matches")
async test_webhook(webhook_url)[source]

Send a test payload to a webhook URL.

Parameters:

webhook_url (str)

Return type:

dict[str, Any]

class vairified.client.MembersResource[source]

Bases: _Resource

Member operations — get a single member, auto-paginating search, and polling for rating change notifications.

Parameters:

client (Vairified)

async get(player_id, *, sport=None)[source]

Get a connected member by external ID.

Requires an active OAuth connection between your partner app and the player. Use the OAuth flow on client.oauth first.

Parameters:
  • player_id (str) – External player ID in vair_mem_xxx format.

  • sport (str | list[str] | None (default: None)) – Optional sport filter. Pass a single sport code to get ratings for just that sport, or a list to get multiple. When omitted, the response contains every sport the player has ratings in.

Raises:
  • NotFoundError – If the external ID is invalid or unknown.

  • VairifiedError – If the player has not connected to your app (403) or if the API request otherwise fails.

Return type:

Member

Example:

member = await client.members.get("vair_mem_xxx")
print(member.display_name, member.rating_for("pickleball"))

# Just pickleball
member = await client.members.get("vair_mem_xxx", sport="pickleball")

# Multiple sports
member = await client.members.get(
    "vair_mem_xxx",
    sport=["pickleball", "padel"],
)
async search(*, sport=None, name=None, member_id=None, city=None, state=None, country=None, zip=None, location=None, gender=None, vairified_only=None, wheelchair=None, rating_min=None, rating_max=None, age=None, age_min=None, age_max=None, sort_by=None, sort_order='desc', page_size=20, max_results=None)[source]

Search for players, yielding each match as an Member.

This is an auto-paginating async iterator — it fetches pages from the server lazily as you iterate, so you can stream through thousands of results without holding them all in memory:

async for member in client.members.search(city="Austin"):
    print(member.display_name, member.rating_for("pickleball"))

Stop early by break-ing out of the loop, or cap the total number of results with max_results.

Parameters:
  • sport (str | list[str] | None (default: None)) – Sport code (or list of codes) to filter ratings by. Omit to get every sport each player has ratings in.

  • name (str | None (default: None)) – Name partial-match (first or last name).

  • member_id (int | str | None (default: None)) – Exact numeric member ID.

  • city (str | None (default: None)) – City filter (partial match, case-insensitive).

  • state (str | None (default: None)) – State code (e.g. "TX").

  • country (str | None (default: None)) – ISO 3166 alpha-2 country code.

  • zip (str | None (default: None)) – ZIP/postal code (exact match).

  • location (str | None (default: None)) – General location search.

  • gender (str | None (default: None)) – "MALE", "FEMALE", or None for any.

  • vairified_only (bool | None (default: None)) – When True, only verified players.

  • wheelchair (bool | None (default: None)) – When True, only wheelchair players.

  • rating_min (float | None (default: None)) – Lower rating bound (2.0-8.0).

  • rating_max (float | None (default: None)) – Upper rating bound (2.0-8.0).

  • age (int | None (default: None)) – Exact age filter.

  • age_min (int | None (default: None)) – Lower age bound.

  • age_max (int | None (default: None)) – Upper age bound.

  • sort_by (str | None (default: None)) – Field to sort by.

  • sort_order (str (default: 'desc')) – "asc" or "desc".

  • page_size (int (default: 20)) – Results per HTTP request. Server cap is 100.

  • max_results (int | None (default: None)) – Optional cap on total results to iterate.

Return type:

AsyncIterator[Member]

async rating_updates()[source]

Poll for rating change notifications for subscribed members.

Returns a list of RatingUpdate objects for every player whose rating has changed since the last poll. Members are considered “subscribed” when they have an active OAuth connection with the user:webhook:subscribe scope.

Return type:

list[RatingUpdate]

async find(name)[source]

Return the first search hit for a name, or None.

Convenience method for the common “look up by name” case:

mike = await client.members.find("Mike Barker")
if mike:
    print(mike.rating_for("pickleball"))
Parameters:

name (str)

Return type:

Member | None

async get_bulk(ids, *, sport=None)[source]

Fetch up to 100 members by their member IDs in one call.

Parameters:
  • ids (Sequence[int]) – Sequence of integer member IDs (max 100).

  • sport (str | None (default: None)) – Optional sport code to filter ratings.

Return type:

list[Member]

Returns:

List of Member objects. Unknown IDs are silently omitted – the list may be shorter than ids.

Raises:

ValueError – If more than 100 IDs are provided.

Example:

members = await client.members.get_bulk([4873327, 4873328])
for m in members:
    print(m.name, m.rating_for("pickleball"))
class vairified.client.OAuthResource[source]

Bases: _Resource

OAuth 2.0 flow for obtaining player consent.

Typical flow:

  1. Call authorize() to start an authorization — you get a URL to redirect the player to.

  2. The player approves on the Vairified site and gets redirected to your redirect_uri with a code query parameter.

  3. Call exchange_token() to swap the code for access and refresh tokens plus the player’s UUID.

  4. Store the refresh token and call refresh() when the access token expires.

  5. Call revoke() to disconnect a player from your app.

Parameters:

client (Vairified)

async authorize(redirect_uri, *, scopes=None, state=None)[source]

Start an OAuth authorization flow.

Parameters:
  • redirect_uri (str) – Your application’s callback URL.

  • scopes (list[Literal['user:profile:read', 'user:profile:email', 'user:rating:read', 'user:rating:history', 'user:match:submit', 'user:webhook:subscribe']] | None (default: None)) – Scopes to request. Defaults to ["user:profile:read", "user:rating:read"]. user:profile:read is always added if missing.

  • state (str | None (default: None)) – CSRF protection token — persist and verify on callback.

Raises:

OAuthError – If a requested scope is invalid.

Return type:

AuthorizationResponse

async exchange_token(code, redirect_uri)[source]

Exchange an authorization code for access and refresh tokens.

Parameters:
  • code (str)

  • redirect_uri (str)

Return type:

TokenResponse

async refresh(refresh_token)[source]

Refresh an expired access token using a refresh token.

Parameters:

refresh_token (str)

Return type:

TokenResponse

async revoke(player_id)[source]

Revoke a player’s OAuth connection to your app.

Parameters:

player_id (str)

Return type:

dict[str, Any]

async available_scopes()[source]

Return the list of OAuth scopes the server currently supports.

Return type:

list[dict[str, str]]

class vairified.client.Vairified[source]

Bases: object

Async client for the Vairified Partner API.

The client is organized around sub-resources that mirror the REST structure — client.members, client.matches, client.oauth, client.leaderboard. Each sub-resource is a thin wrapper around the HTTP layer on this object.

Parameters:
  • api_key (str | None (default: None)) – Partner API key (vair_pk_...). Falls back to the VAIRIFIED_API_KEY environment variable if not supplied.

  • env (str | None (default: None)) – Environment preset — "production" (default), "staging", or "local". Overridden by base_url.

  • base_url (str | None (default: None)) – Explicit base URL. Takes precedence over env.

  • timeout (float (default: 30.0)) – Request timeout in seconds.

Raises:

ValueError – If no API key is provided.

__init__(api_key=None, *, env=None, base_url=None, timeout=30.0)[source]
Parameters:
  • api_key (str | None (default: None))

  • env (str | None (default: None))

  • base_url (str | None (default: None))

  • timeout (float (default: 30.0))

Return type:

None

async close()[source]

Close the underlying HTTP client. Safe to call multiple times.

Return type:

None

async usage()[source]

API usage statistics for the current API key.

Returns rate-limit status, request counts, and quota usage for monitoring purposes.

Return type:

dict[str, Any]

class vairified.client.WebhooksResource[source]

Bases: _Resource

Webhook delivery inspection.

Parameters:

client (Vairified)

async deliveries(*, event=None, status=None, limit=20, offset=0)[source]

List recent webhook delivery attempts.

Parameters:
  • event (str | None (default: None)) – Filter by event type (e.g. "rating.updated").

  • status (str | None (default: None)) – Filter: "all", "pending", "success", or "failed".

  • limit (int (default: 20)) – Results per page (1-100, default 20).

  • offset (int (default: 0)) – Pagination offset.

Return type:

WebhookDeliveriesResult

Returns:

WebhookDeliveriesResult with entries and total.

Example:

result = await client.webhooks.deliveries(status="failed")
for d in result.deliveries:
    print(d.event, d.status_code, d.error_message)

Models

Vairified SDK Models — Partner API v1 shapes.

All response models are pydantic.BaseModel with model_config = ConfigDict(frozen=True, populate_by_name=True, extra="allow") so they’re immutable, support both snake_case (Python) and camelCase (wire) field names, and tolerate new server-side fields without breaking.

The public surface is designed to feel native:

  • member.name is a property(), not a method — no get_name().

  • member.sport["pickleball"] is dict-like access; SportRating implements __getitem__, __iter__, __contains__, __len__.

  • Every model has a human-readable __repr__ so the REPL is useful.

  • Models work with match statements via pydantic field access.

Breaking from v0.1.x:

The flat single-sport response (member.rating / member.rating_splits) has been replaced by a multi-sport member.sport dict keyed by sport code. The Match class takes teams: list[list[str]] and games: list[Game] instead of team1/team2 plus per-game tuples.

class vairified.models.Gender[source]

Bases: StrEnum

Normalized gender enum returned by the Partner API.

Matches the UPPERCASE tokens emitted by PartnerMember.gender on the backend.

MALE = 'MALE'
FEMALE = 'FEMALE'
OTHER = 'OTHER'
UNKNOWN = 'UNKNOWN'
__new__(value)
class vairified.models.Game[source]

Bases: BaseModel

One scored game within a Match.

scores is one integer per team, in the same order as the parent match’s teams list. For a standard 2-team game scores is [team1_score, team2_score]. The API supports n-team matches by setting a longer list.

All fields except scores are optional overrides of the parent match’s defaults — use them only when a specific game inside the match differs from the rest (e.g. a championship game played to 15 when the rest of the match was to 11).

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

scores: list[int]
identifier: str | None
win_score: int | None
win_by: int | None
class vairified.models.Match[source]

Bases: BaseModel

One match to submit in a MatchBatch.

A match has:

  • teams — a list of teams, each a list of player IDs (external vair_mem_xxx, numeric member IDs, or UUIDs). Supports n-team × n-player matches natively: [[p1, p2], [p3, p4]] for standard doubles, [[p1], [p2]] for singles, [[p1], [p2], [p3]] for a 3-way round robin.

  • games — one or more scored games (e.g. best-of-3 has 2 or 3 entries). Scores in each game are parallel to the teams order.

Every other field is an optional override of the parent MatchBatch default.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

identifier: str
teams: list[list[str]]
games: list[Game]
sport: str | None
bracket: str | None
event: str | None
location: str | None
match_date: str | None
match_source: str | None
match_type: str | None
win_score: int | None
win_by: int | None
extras: dict[str, Any] | None
original_id: str | None
original_type: str | None
club_id: int | None
property num_games: int

Number of scored games in this match (best-of-N count).

property num_teams: int

Number of teams in this match.

class vairified.models.MatchBatch[source]

Bases: BaseModel

Compressed bulk match submission.

Top-level fields are defaults applied to every match in the matches list. Any match can override any field. sport, win_score, and win_by are required at the batch level — partners must tell the rater which sport the matches are in and what the winning conditions were so scores can be interpreted correctly.

Example:

batch = MatchBatch(
    sport="pickleball",
    win_score=11,
    win_by=2,
    bracket="4.0 Doubles",
    event="Weekly League",
    match_date="2026-04-11T14:00:00Z",
    matches=[
        Match(
            identifier="m1",
            teams=[["vair_mem_aaa", "vair_mem_bbb"],
                   ["vair_mem_ccc", "vair_mem_ddd"]],
            games=[Game(scores=[11, 8]),
                   Game(scores=[11, 5])],
        ),
    ],
)
result = await client.matches.submit(batch)
Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

sport: str
win_score: int
win_by: int
matches: list[Match]
bracket: str | None
event: str | None
location: str | None
match_date: str | None
match_source: str | None
match_type: str | None
extras: dict[str, Any] | None
identifier: str | None
original_id: str | None
original_type: str | None
club_id: int | None
dry_run: bool | None
class vairified.models.MatchBatchResult[source]

Bases: BaseModel

Result of a Vairified.matches.submit() call.

success is True only when every match in the batch was accepted. Check errors for per-match validation failures.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

success: bool
num_matches: int
num_games: int
dry_run: bool | None
message: str | None
errors: list[str] | None
property ok: bool

Shorthand: successful submission with zero errors.

property is_dry_run: bool

Whether this was a dry-run (validation only, nothing persisted).

class vairified.models.Member[source]

Bases: BaseModel

A partner-facing player record.

Returned by Vairified.members.get() (full detail, requires an active OAuth connection) and Vairified.members.search() (limited detail for public search).

Rating data lives under sport — a dict keyed by sport code. The backend returns only the sports the player has ratings in, or only the sports requested via the ?sport= query filter. Use rating_for() to fetch the primary rating for a specific sport with a sensible default.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

member_id: int
id: str | None
first_name: str
last_name: str
full_name: str
display_name: str
age: int | None
city: str | None
state: str | None
zip: str | None
country: str | None
gender: Gender | None
status: MemberStatus
sport: dict[str, SportRating]
active_leagues: list[str] | None
email: str | None
granted_scopes: list[str] | None
property name: str

Full name — alias for full_name, matching common usage.

property sports: list[str]

The list of sport codes this player has ratings in.

rating_for(sport='pickleball')[source]

Primary rating for a given sport.

Parameters:

sport (str (default: 'pickleball')) – Sport code, defaults to "pickleball".

Return type:

float | None

Returns:

The primary rating value, or None if the player has no ratings for that sport.

Example:

member.rating_for()              # pickleball
member.rating_for("padel")       # padel
split(key, sport='pickleball')[source]

Get a specific rating split for a sport.

Parameters:
  • key (str) – Split key, e.g. "overall-open" or "singles-12-13".

  • sport (str (default: 'pickleball')) – Sport code, defaults to "pickleball".

Return type:

RatingSplit | None

class vairified.models.MemberStatus[source]

Bases: BaseModel

Global status flags for a player.

Grouped into a sub-object rather than top-level booleans so that inspection (pprint, repr, JSON) keeps all is_* flags visually clustered.

Only the genuinely global flags live here. VAIRification and VAIR-Pro status are per-sport (Vairified#783) and live on each SportRating (member.sport["pickleball"].is_vairified).

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

is_wheelchair: bool
is_ambassador: bool
is_connected: bool
class vairified.models.RatingSplit[source]

Bases: BaseModel

One slice of a player’s rating for a specific category × age bracket.

Keys in SportRating.rating_splits are strings like "overall-open", "singles-12-13", or "overall-40+".

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

rating: float
abbr: str
class vairified.models.RatingUpdate[source]

Bases: BaseModel

A single rating change notification.

Returned by Vairified.members.rating_updates() (polling) and delivered via webhook callbacks to partners that have registered a webhook URL.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

member_id: int
id: str | None
display_name: str | None
sport: str | None
previous_rating: float | None
new_rating: float | None
changed_at: str | None
rating_splits: dict[str, RatingSplit] | None
property delta: float | None

Rating change amount. None when either rating is missing.

property improved: bool

True when the new rating is strictly higher than the previous.

class vairified.models.SearchFilters[source]

Bases: BaseModel

Filters accepted by Vairified.members.search().

Most users won’t construct this directly — the search() method accepts keyword arguments and builds it internally. But it’s exposed so you can inspect the full set of available filters in one place.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

sport: str | None
member: str | None
location: str | None
country: str | None
city: str | None
state: str | None
zip: str | None
age_filter_type: str | None
age1: int | None
age2: int | None
gender: str | None
wheelchair: bool | None
vairified: bool | None
rating1: float | None
rating2: float | None
sort_field: str | None
sort_direction: str | None
offset: int | None
limit: int | None
to_query_params()[source]

Serialize to the wire-format dict expected by httpx params=.

Return type:

dict[str, Any]

class vairified.models.SportRating[source]

Bases: BaseModel

A player’s ratings for a single sport.

The top-level rating / abbr is the primary rating for that sport (conventionally the overall-open bracket). Every category × age bracket the player has played is also available under rating_splits, keyed by {category}-{bracketCode}.

This class is dict-like — you can access splits by subscript, iterate them, check membership, and get the length without touching rating_splits directly:

overall = member.sport["pickleball"]["overall-open"].rating
for key, split in member.sport["pickleball"]:
    print(key, split.rating)
if "singles-40+" in member.sport["pickleball"]:
    ...
print(len(member.sport["pickleball"]), "splits")
Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

rating: float
abbr: str
rating_splits: dict[str, RatingSplit]
is_vairified: bool

Player is VAIRified in this sport (has a verified, non-recreational rating).

is_rater: bool

Active VAIR Pro (can rate) in this sport. Alias of is_vair_pro.

is_vair_pro: bool

Player is an active VAIR Pro (can rate) in this sport.

is_vair_pro_status: Literal['PENDING', 'ACTIVE'] | None

VAIR-Pro lifecycle status here: "ACTIVE", "PENDING", or None.

keys()[source]

Split keys (e.g. "overall-open", "singles-12-13").

Return type:

Any

get(key, default=None)[source]

Dict-style safe lookup.

Parameters:
Return type:

RatingSplit | None

class vairified.models.TournamentImportResult[source]

Bases: BaseModel

Result of a tournament import submission.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

success: bool
matches_imported: int
games_recorded: int
ghost_players_created: int
existing_players_matched: int
dry_run: bool | None
message: str | None
errors: list[str] | None
class vairified.models.WebhookDelivery[source]

Bases: BaseModel

A single webhook delivery attempt.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

id: str
event: str
url: str
status_code: int | None
response_body: str | None
error_message: str | None
attempts: int
max_attempts: int
last_attempt_at: str
next_retry_at: str | None
completed_at: str | None
created_at: str
payload: dict[str, Any]
class vairified.models.WebhookDeliveriesResult[source]

Bases: BaseModel

Paginated list of webhook delivery attempts.

Parameters:

data (Any)

model_config: ClassVar[ConfigDict] = {'extra': 'allow', 'frozen': True, 'populate_by_name': True, 'validate_by_alias': True, 'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

deliveries: list[WebhookDelivery]
total: int

OAuth

Vairified OAuth Helpers

Utilities for implementing the “Connect with Vairified” OAuth flow.

vairified.oauth.OAuthScope

Scope string literal — the union of every scope name the Vairified OAuth server accepts. Use this type in your own signatures to get autocomplete and type-checking for the scope strings you pass.

alias of Literal[‘user:profile:read’, ‘user:profile:email’, ‘user:rating:read’, ‘user:rating:history’, ‘user:match:submit’, ‘user:webhook:subscribe’]

class vairified.oauth.OAuthConfig[source]

Bases: object

OAuth configuration for a partner application.

Variables:
  • api_key – Partner API key.

  • redirect_uri – Your application’s callback URL.

  • base_url – Vairified API base URL.

Parameters:
  • api_key (str)

  • redirect_uri (str)

  • base_url (str (default: 'https://api-next.vairified.com/api/v1'))

  • client_id (Optional[str] (default: None))

api_key: str
redirect_uri: str
base_url: str = 'https://api-next.vairified.com/api/v1'
client_id: str | None = None

Your app’s client_id — the PartnerApp.slug Vairified assigned you (e.g. "dinkr"). Required by the browser GET /partner/oauth/authorize endpoint to identify your app; without it the authorization page rejects the request. Only needed for this pure-frontend URL helper — the recommended OAuthResource.authorize() flow identifies your app by API key.

__init__(api_key, redirect_uri, base_url='https://api-next.vairified.com/api/v1', client_id=None)
Parameters:
  • api_key (str)

  • redirect_uri (str)

  • base_url (str (default: 'https://api-next.vairified.com/api/v1'))

  • client_id (Optional[str] (default: None))

Return type:

None

class vairified.oauth.AuthorizationResponse[source]

Bases: object

Response from starting an OAuth authorization.

Variables:
  • authorization_url – Full URL to redirect the user to.

  • code – Authorization code (for internal tracking).

  • state – CSRF state parameter.

Parameters:
authorization_url: str
code: str
state: str | None = None
__init__(authorization_url, code, state=None)
Parameters:
Return type:

None

class vairified.oauth.TokenResponse[source]

Bases: object

Response from exchanging an authorization code for tokens.

Variables:
  • access_token – Access token for API requests.

  • refresh_token – Refresh token for obtaining new access tokens.

  • expires_in – Token expiration in seconds.

  • scope – Granted scopes.

  • player_id – Connected player’s external ID.

Parameters:
access_token: str
refresh_token: str | None
expires_in: int
scope: list[str]
player_id: str
__init__(access_token, refresh_token, expires_in, scope, player_id)
Parameters:
Return type:

None

vairified.oauth.get_authorization_url(config, scopes=None, state=None)[source]

Build the URL to redirect users to for OAuth authorization.

This is a helper for building the URL manually. In most cases, you should use the Vairified client’s OAuth methods instead.

Parameters:
  • config (OAuthConfig) – OAuth configuration.

  • scopes (Optional[list[str]] (default: None)) – Permission scopes to request.

  • state (Optional[str] (default: None)) – CSRF protection state parameter.

Return type:

str

Returns:

URL to redirect the user to.

Example:

config = OAuthConfig(
    api_key="vair_pk_xxx",
    redirect_uri="https://myapp.com/oauth/callback",
)
url = get_authorization_url(
    config, scopes=["user:profile:read", "user:rating:read"]
)
# Redirect user to this URL
vairified.oauth.validate_scope(scope)[source]

Check if a scope is valid.

Parameters:

scope (str) – Scope string to validate.

Return type:

bool

Returns:

True if scope is valid.

vairified.oauth.describe_scope(scope)[source]

Get a human-readable description of a scope.

Parameters:

scope (str) – Scope string.

Return type:

str

Returns:

Description of what the scope grants access to.

vairified.oauth.describe_scopes(scopes)[source]

Get descriptions for multiple scopes.

Parameters:

scopes (list[str]) – List of scope strings.

Return type:

list[dict[str, str]]

Returns:

List of dicts with ‘scope’ and ‘description’ keys.

Errors

Vairified SDK Errors

Custom exception classes for API errors.

exception vairified.errors.VairifiedError[source]

Bases: Exception

Base exception for Vairified API errors.

Variables:
  • message – Error message.

  • status_code – HTTP status code (if applicable).

  • response – Raw response body (if available).

Parameters:
__init__(message, status_code=None, response=None)[source]

Initialize the error.

Parameters:
  • message (str) – Human-readable error message.

  • status_code (Optional[int] (default: None)) – HTTP status code.

  • response (Optional[Any] (default: None)) – Raw response body.

exception vairified.errors.RateLimitError[source]

Bases: VairifiedError

Raised when rate limit is exceeded.

Variables:

retry_after – Seconds to wait before retrying.

Parameters:
  • message (str (default: 'Rate limit exceeded'))

  • retry_after (Optional[int] (default: None))

__init__(message='Rate limit exceeded', retry_after=None, **kwargs)[source]

Initialize rate limit error.

Parameters:
  • message (str (default: 'Rate limit exceeded')) – Error message.

  • retry_after (Optional[int] (default: None)) – Seconds to wait before retrying.

exception vairified.errors.AuthenticationError[source]

Bases: VairifiedError

Raised when authentication fails.

Typically means the API key is invalid or expired.

Parameters:

message (str (default: 'Invalid API key'))

__init__(message='Invalid API key', **kwargs)[source]

Initialize authentication error.

Parameters:

message (str (default: 'Invalid API key')) – Error message.

exception vairified.errors.NotFoundError[source]

Bases: VairifiedError

Raised when a resource is not found.

Typically means the requested member/player doesn’t exist.

Parameters:

message (str (default: 'Resource not found'))

__init__(message='Resource not found', **kwargs)[source]

Initialize not found error.

Parameters:

message (str (default: 'Resource not found')) – Error message.

exception vairified.errors.ValidationError[source]

Bases: VairifiedError

Raised when request validation fails.

Check the response body for details on which fields failed validation.

Parameters:

message (str (default: 'Validation error'))

__init__(message='Validation error', **kwargs)[source]

Initialize validation error.

Parameters:

message (str (default: 'Validation error')) – Error message.

exception vairified.errors.OAuthError[source]

Bases: VairifiedError

Raised when an OAuth operation fails.

This can occur during authorization, token exchange, refresh, or revocation.

Variables:

error_code – OAuth error code (e.g., ‘invalid_grant’, ‘expired_token’).

Parameters:
  • message (str (default: 'OAuth error'))

  • error_code (Optional[str] (default: None))

__init__(message='OAuth error', error_code=None, **kwargs)[source]

Initialize OAuth error.

Parameters:
  • message (str (default: 'OAuth error')) – Error message.

  • error_code (Optional[str] (default: None)) – OAuth error code.