Skip to main content

Official Python SDK for the Vairified Partner API

Project description

Vairified Python SDK

Official Python SDK for the Vairified Partner API
Player ratings, search, and match submission

CI Version 0.1.0 Python 3.12+ PyPI


Python SDK for integrating with the Vairified player rating platform. Async-first, object-oriented design for easy integration.

Installation

pip install vairified

Or with UV:

uv add vairified

Quick Start

import asyncio
from vairified import Vairified

async def main():
    async with Vairified(api_key="vair_pk_xxx") as client:
        # Get a member - automatically subscribes to their rating updates
        member = await client.get_member("clerk_user_123")
        print(f"{member.name}: {member.rating}")
        print(f"Verified: {member.is_vairified}")
        print(f"Best rating: {member.rating_splits.best}")

asyncio.run(main())

Features

Search for Players

async with Vairified(api_key="vair_pk_xxx") as client:
    # Search with filters
    results = await client.search(
        city="Austin",
        state="TX",
        rating_min=3.5,
        rating_max=4.5,
        vairified_only=True,
        limit=20,
    )

    # Iterate over results
    for player in results:
        print(f"{player.name}: {player.rating}")

    # Pagination
    print(f"Page {results.page} of {results.pages}")
    if results.has_more:
        next_page = await results.next_page()

Find a Player by Name

async with Vairified(api_key="vair_pk_xxx") as client:
    player = await client.find_player("John Smith")
    if player:
        print(f"Found: {player.name} ({player.rating})")

Submit Match Results

from datetime import datetime
from vairified import Vairified, Match

async with Vairified(api_key="vair_pk_xxx") as client:
    # Doubles match: 11-9, 11-7
    match = Match(
        event="Weekly League",
        bracket="4.0 Doubles",
        date=datetime.now(),
        team1=("player1_id", "player2_id"),
        team2=("player3_id", "player4_id"),
        scores=[(11, 9), (11, 7)],
    )

    result = await client.submit_match(match)
    if result:
        print(f"Submitted {result.num_games} games")

    # Singles match
    singles = Match(
        event="Club Singles",
        bracket="Open Singles",
        date=datetime.now(),
        team1=("player1_id",),
        team2=("player2_id",),
        scores=[(11, 8), (9, 11), (11, 6)],
    )
    await client.submit_match(singles)

Get Rating Updates

async with Vairified(api_key="vair_pk_xxx") as client:
    # First, look up members to subscribe to their updates
    await client.get_member("user_1")
    await client.get_member("user_2")

    # Later, check for rating changes
    updates = await client.get_rating_updates()
    for update in updates:
        direction = "improved" if update.improved else "dropped"
        print(f"{update.member_id} {direction}: {update.previous_rating:.2f} -> {update.new_rating:.2f}")

        # Get the full member profile
        member = await update.get_member()

OAuth Connect Flow

Connect players to your application using OAuth to access their profile and rating data.

import secrets
from vairified import Vairified, OAuthError

async with Vairified(api_key="vair_pk_xxx") as client:
    # Step 1: Start authorization
    state = secrets.token_urlsafe(32)  # CSRF protection
    auth = await client.start_oauth(
        redirect_uri="https://myapp.com/oauth/callback",
        scopes=["profile:read", "rating:read", "match:submit"],
        state=state,
    )
    
    # Redirect user to auth.authorization_url
    print(f"Redirect to: {auth.authorization_url}")
# Step 2: Handle callback (in your /oauth/callback route)
async with Vairified(api_key="vair_pk_xxx") as client:
    # Exchange code for tokens
    tokens = await client.exchange_token(
        code=request.query_params["code"],
        redirect_uri="https://myapp.com/oauth/callback",
    )
    
    # Store tokens securely
    player_id = tokens.player_id
    access_token = tokens.access_token
    refresh_token = tokens.refresh_token
    
    # Now you can access the player's data
    member = await client.get_member(player_id)
    print(f"Connected: {member.name} ({member.rating})")
# Step 3: Refresh expired tokens
async with Vairified(api_key="vair_pk_xxx") as client:
    try:
        new_tokens = await client.refresh_access_token(stored_refresh_token)
        # Update stored tokens
    except OAuthError as e:
        if e.error_code == "invalid_grant":
            # Token revoked, user needs to re-authorize
            pass

Available OAuth Scopes

Scope Description
profile:read Name, location, verification status
profile:email Email address
rating:read Current rating and rating splits
rating:history Complete rating history
match:submit Submit matches on behalf of user
webhook:subscribe Rating change notifications

Revoke Connection

async with Vairified(api_key="vair_pk_xxx") as client:
    await client.revoke_connection("vair_mem_xxx")

Models

Player

player.id              # UUID or member ID
player.member_id       # Legacy member ID
player.name            # "John Smith"
player.first_name      # "John"
player.last_name       # "Smith"
player.rating          # 4.25
player.is_vairified    # True/False
player.rating_splits   # RatingSplits object
player.city            # "Austin"
player.state           # "TX"
player.verified_rating # Best verified rating

Member (extends Player)

member.email           # Email address
await member.refresh() # Refresh data from API

RatingSplits

Access ratings by category:

splits = member.rating_splits
splits.open           # Open division rating
splits.gender         # Same-gender doubles rating
splits.mixed          # Mixed doubles rating
splits.recreational   # Recreational rating
splits.singles        # Singles rating
splits.best           # Best available rating
splits.get("50_and_up")  # Age bracket rating

Match

match = Match(
    event="Weekly League",
    bracket="4.0 Doubles",
    date=datetime.now(),
    team1=("id1", "id2"),        # Player IDs for team 1
    team2=("id3", "id4"),        # Player IDs for team 2
    scores=[(11, 9), (11, 7)],   # Game scores
    location="Austin Club",      # Optional
    match_type="SIDEOUT",        # Default: "SIDEOUT"
    source="PARTNER",            # Default: "PARTNER"
)

match.format         # "DOUBLES" or "SINGLES"
match.winner         # 1 or 2 (0 if tie)
match.score_summary  # "11-9, 11-7"
match.identifier     # Auto-generated unique ID

MatchResult

result = await client.submit_matches([match1, match2])
result.success       # True/False
result.num_matches   # Number processed
result.num_games     # Games recorded
result.dry_run       # True if validation only
result.message       # Human-readable message
result.errors        # List of errors
bool(result)         # True if successful

SearchResults

results.players      # List of Player objects
results.total        # Total matching players
results.page         # Current page
results.pages        # Total pages
results.has_more     # More pages available
await results.next_page()  # Get next page
bool(results)        # True if has players

Configuration

from vairified import Vairified

# Basic usage
client = Vairified(api_key="vair_pk_xxx")

# Use staging for development/testing
client = Vairified(api_key="vair_pk_xxx", env="staging")

# Custom configuration
client = Vairified(
    api_key="vair_pk_xxx",
    timeout=30.0,
)

Environment Variables

export VAIRIFIED_API_KEY="vair_pk_xxx"
# API key read from environment
async with Vairified() as client:
    ...

Dry-Run Mode (Dev Keys)

If your API key has the dry-run scope, match submissions are validated but not persisted. This is useful for testing integrations without affecting production data.

# With a dry-run API key
async with Vairified(api_key="vair_pk_dev_xxx") as client:
    result = await client.submit_matches([match1, match2])
    
    if result.dry_run:
        print(f"Validation passed: {result.num_games} games would be created")
        print(result.message)

Request a dry-run API key from your Vairified partner contact for integration testing.

Error Handling

from vairified import (
    Vairified,
    VairifiedError,
    RateLimitError,
    AuthenticationError,
    NotFoundError,
    OAuthError,
)

async with Vairified(api_key="vair_pk_xxx") as client:
    try:
        member = await client.get_member("user_123")
    except RateLimitError as e:
        print(f"Rate limited. Retry after {e.retry_after} seconds")
    except AuthenticationError:
        print("Invalid API key")
    except NotFoundError:
        print("Member not found")
    except OAuthError as e:
        print(f"OAuth error: {e.message} (code: {e.error_code})")
    except VairifiedError as e:
        print(f"API error: {e.message} (status: {e.status_code})")

Development

git clone https://github.com/Vairified/vairified.py.git
cd vairified.py
uv sync --all-extras
uv run pytest

License

MIT License - see LICENSE for details.


vairified.com · Documentation · Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vairified-0.1.0.tar.gz (65.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vairified-0.1.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file vairified-0.1.0.tar.gz.

File metadata

  • Download URL: vairified-0.1.0.tar.gz
  • Upload date:
  • Size: 65.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for vairified-0.1.0.tar.gz
Algorithm Hash digest
SHA256 551bf436882684799b8b61d16a568ecbc5835c62050af20aa8479501464d95d3
MD5 6202a7c61ce04e7ff71d6ed406b2f8f2
BLAKE2b-256 63cb9a9deb7151479bc58395f3d2d8aa6726c9e972c69851068d2d077483cd81

See more details on using hashes here.

Provenance

The following attestation bundles were made for vairified-0.1.0.tar.gz:

Publisher: release.yml on Vairified/vairified.py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vairified-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vairified-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for vairified-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5f7f7b125ef011ae06d0b195f4e2aa3a327637c1d8b95be2ec9dec3c10a12b7a
MD5 76f98cece7f103e8132cbd87f27f8843
BLAKE2b-256 a395fa935a15c912eaca5c5bf51e96fe29c1025662201ff7f49d59ff82c78197

See more details on using hashes here.

Provenance

The following attestation bundles were made for vairified-0.1.0-py3-none-any.whl:

Publisher: release.yml on Vairified/vairified.py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page