Official Python SDK for the Vairified Partner API
Player ratings, search, and match submission
Python SDK for integrating with the Vairified player rating platform. Async-first, object-oriented design for easy integration.
pip install vairifiedOr with UV:
uv add vairifiedimport 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())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()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})")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)async with Vairified(api_key="vair_pk_xxx") as client:
# Get global doubles leaderboard
leaderboard = await client.get_leaderboard()
# Get state-level singles leaderboard
tx_leaderboard = await client.get_leaderboard(
category="singles",
scope="state",
state="TX",
limit=50,
)
# Get 50+ age bracket with verified players only
senior_leaderboard = await client.get_leaderboard(
age_bracket="50+",
verified_only=True,
)
# Display results
for player in leaderboard["players"]:
print(f"#{player['rank']} {player['displayName']}: {player['rating']}")
# Get a specific player's rank
rank = await client.get_player_rank(
"vair_mem_xxx",
category="doubles",
context_size=5,
)
print(f"Rank: #{rank['rank']} (top {rank['percentile']:.1f}%)")
# Get available categories
categories = await client.get_leaderboard_categories()
print("Categories:", [c["name"] for c in categories["categories"]])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()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| 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 |
async with Vairified(api_key="vair_pk_xxx") as client:
await client.revoke_connection("vair_mem_xxx")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 ratingmember.email # Email address
await member.refresh() # Refresh data from APIAccess 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 ratingmatch = 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 IDresult = 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 successfulresults.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 playersfrom 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,
)export VAIRIFIED_API_KEY="vair_pk_xxx"# API key read from environment
async with Vairified() as client:
...Your API key determines which endpoints you can access. The scope system uses a hierarchy:
admin → write → read → granular scopes
| Scope | Access |
|---|---|
admin |
Full access to all endpoints |
write |
All read + write operations |
read |
All read operations (search, leaderboard, member) |
leaderboard:read |
Leaderboard endpoints only |
player:search |
Player search only |
member:read |
Connected member data only |
match:submit |
Submit match results |
tournament:import |
Import tournament data |
dry-run |
Validate writes without persisting |
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.
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})")git clone https://github.com/Vairified/vairified.py.git
cd vairified.py
uv sync --all-extras
uv run pytestMIT License - see LICENSE for details.