Technical Integration Guide
Complete developer guide for integrating with the AltSportsLeagues.ai API. This covers authentication, endpoints, SDKs, testing, and production best practices.
Quick Start
Authentication
All API requests use API key authentication via the X-API-Key header:
curl https://api.altsportsleagues.ai/v1/leagues \
-H "X-API-Key: your_api_key_here"Environment-specific keys:
- Production:
https://api.altsportsleagues.ai - Sandbox:
https://sandbox-api.altsportsleagues.ai
First API Call
Test your credentials:
curl https://api.altsportsleagues.ai/health \
-H "X-API-Key: your_api_key_here"Expected response:
{
"status": "healthy",
"version": "1.0.0",
"timestamp": "2025-01-18T10:30:00Z"
}Core API Endpoints
League Discovery
Search and discover leagues:
GET /v1/leagues?sport=mma&tier=1&limit=10Query Parameters:
sport- Filter by sport type (mma, esports, etc.)region- Geographic region filtertier- League tier (1-5)status- active, onboarding, archivedlimit- Results per page (max 100)offset- Pagination offset
Response:
{
"data": [{
"id": "league_abc123",
"name": "Global Fighting Championship",
"sport": "mma",
"tier": 1,
"region": "north_america",
"metadata": {
"founded": "2018",
"total_events": 156
}
}],
"pagination": {
"total": 47,
"has_more": true
}
}League Details
Get comprehensive league information:
GET /v1/leagues/{league_id}"}Events & Schedules
Access league events:
GET /v1/leagues/{league_id}"}/events?status=upcoming&limit=5Live Scores
Real-time event data:
GET /v1/events/{event_id}"}/liveAthlete Data
Access player/fighter statistics:
GET /v1/athletes/{athlete_id}"}SDK Integration
Python Client
import os
import requests
from typing import Dict, Optional
class AltSportsLeaguesClient:
"""Official Python client for AltSportsLeagues.ai API"""
def __init__(self, api_key: str, base_url: str = "https://api.altsportsleagues.ai"):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
"X-API-Key": api_key,
"Content-Type": "application/json"
})
def get_leagues(self, sport: Optional[str] = None, tier: Optional[int] = None) -> Dict:
"""Fetch leagues with optional filters"""
params = {}
if sport:
params["sport"] = sport
if tier:
params["tier"] = tier
response = self.session.get(f"{self.base_url}/v1/leagues", params=params)
response.raise_for_status()
return response.json()
def get_league(self, league_id: str) -> Dict:
"""Get detailed league information"""
response = self.session.get(f"{self.base_url}/v1/leagues/{league_id}"}")
response.raise_for_status()
return response.json()
def get_live_scores(self, event_id: str) -> Dict:
"""Get real-time scores"""
response = self.session.get(f"{self.base_url}/v1/events/{event_id}"}/live")
response.raise_for_status()
return response.json()
# Usage
client = AltSportsLeaguesClient(os.environ["ALTSPORTSLEAGUES_API_KEY"])
leagues = client.get_leagues(sport="mma", tier=1)JavaScript/TypeScript Client
import axios, { AxiosInstance } from 'axios';
interface LeagueQuery {
sport?: string;
tier?: number;
limit?: number;
}
class AltSportsLeaguesClient {
private client: AxiosInstance;
constructor(apiKey: string, baseURL: string = 'https://api.altsportsleagues.ai') {
this.client = axios.create({
baseURL,
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json',
},
timeout: 30000,
});
}
async getLeagues(query: LeagueQuery = {}) {
const response = await this.client.get('/v1/leagues', { params: query });
return response.data;
}
async getLeague(leagueId: string) {
const response = await this.client.get(`/v1/leagues/${leagueId}`);
return response.data;
}
async getLiveScores(eventId: string) {
const response = await this.client.get(`/v1/events/${eventId}/live`);
return response.data;
}
}
// Usage
const client = new AltSportsLeaguesClient(process.env.ALTSPORTSLEAGUES_API_KEY!);
const leagues = await client.getLeagues({ sport: 'mma', tier: 1 });Go Client
package altsportsleagues
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
type Client struct {
APIKey string
BaseURL string
HTTPClient *http.Client
}
func NewClient(apiKey string) *Client {
return &Client{
APIKey: apiKey,
BaseURL: "https://api.altsportsleagues.ai",
HTTPClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *Client) GetLeagues(sport string, tier int) ([]League, error) {
url := fmt.Sprintf("%s/v1/leagues?sport=%s&tier=%d", c.BaseURL, sport, tier)
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("X-API-Key", c.APIKey)
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result LeaguesResponse
json.NewDecoder(resp.Body).Decode(&result)
return result.Data, nil
}Webhook Integration
Setup Webhook Endpoint
Configure webhook receiver with signature verification:
from fastapi import FastAPI, Request, HTTPException, Header
import hmac
import hashlib
import json
app = FastAPI()
WEBHOOK_SECRET = os.environ["ALTSPORTSLEAGUES_WEBHOOK_SECRET"]
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
"""Verify webhook signature using HMAC-SHA256"""
expected_signature = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected_signature}"}", signature)
@app.post("/webhooks/altsportsleagues")
async def handle_webhook(
request: Request,
x_webhook_signature: str = Header(None)
):
"""Handle incoming webhooks"""
body = await request.body()
# Verify signature
if not verify_webhook_signature(body, x_webhook_signature, WEBHOOK_SECRET):
raise HTTPException(status_code=403, detail="Invalid signature")
payload = json.loads(body)
event_type = payload.get("type")
data = payload.get("data")
# Route to handlers
if event_type == "event.completed":
await handle_event_completed(data)
elif event_type == "result.updated":
await handle_result_updated(data)
return {"status": "received"}Webhook Events
Available event types:
event.created- New event scheduledevent.updated- Event details changedevent.started- Event went liveevent.completed- Event finishedresult.updated- Result data updated
Real-Time Streaming
Server-Sent Events (SSE)
// Subscribe to live event updates
const eventSource = new EventSource(
`https://api.altsportsleagues.ai/v1/events/${eventId}/stream?api_key=${apiKey}`
);
eventSource.onmessage = (event) => {
const update = JSON.parse(event.data);
updateScoreboard(update);
};
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
};WebSocket Connection
import asyncio
import websockets
import json
async def subscribe_to_live_event(event_id: str, api_key: str):
"""Subscribe to live updates via WebSocket"""
uri = f"wss://api.altsportsleagues.ai/v1/ws?api_key={api_key}"}"
async with websockets.connect(uri) as websocket:
# Subscribe to event
await websocket.send(json.dumps({
"action": "subscribe",
"event_id": event_id
}))
# Listen for updates
while True:
message = await websocket.recv()
update = json.loads(message)
print(f"Live update: {update}"}")Error Handling
HTTP Status Codes
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Process response |
| 400 | Bad Request | Check payload |
| 401 | Unauthorized | Verify API key |
| 404 | Not Found | Verify resource ID |
| 429 | Rate Limited | Implement backoff |
| 500 | Server Error | Retry with backoff |
Retry Logic with Exponential Backoff
import time
from functools import wraps
def retry_with_backoff(max_retries=3, base_delay=1.0):
"""Decorator to retry failed requests"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
retries = 0
while retries < max_retries:
try:
return func(*args, **kwargs)
except (ConnectionError, RateLimitError) as e:
retries += 1
if retries >= max_retries:
raise
delay = base_delay * (2 ** (retries - 1))
time.sleep(delay)
raise Exception(f"Max retries exceeded")
return wrapper
return decorator
@retry_with_backoff(max_retries=3)
def fetch_leagues_with_retry(client):
return client.get_leagues(sport="mma")Rate Limiting
Rate Limit Tiers
| Tier | Requests/Minute | Requests/Day |
|---|---|---|
| Free | 60 | 10,000 |
| Standard | 300 | 100,000 |
| Premium | 1,000 | 1,000,000 |
| Enterprise | Custom | Custom |
Rate Limit Headers
Every API response includes:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 245
X-RateLimit-Reset: 1699564800Handling Rate Limits
def respect_rate_limits(response):
"""Check rate limit headers"""
remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
reset = int(response.headers.get("X-RateLimit-Reset", 0))
if remaining < 10: # Approaching limit
wait_time = max(0, reset - time.time())
time.sleep(wait_time)Testing
Sandbox Environment
Use sandbox for testing:
https://sandbox-api.altsportsleagues.aiFeatures:
- Test data with realistic records
- Full API functionality
- Data resets daily at 00:00 UTC
Integration Tests
def test_authentication():
"""Test API key authentication"""
client = AltSportsLeaguesClient(os.environ["SANDBOX_API_KEY"])
health = client._request("GET", "/health")
assert health["status"] == "healthy"
def test_league_crud():
"""Test CRUD operations"""
client = AltSportsLeaguesClient(os.environ["SANDBOX_API_KEY"])
# Fetch leagues
leagues = client.get_leagues(sport="mma", limit=10)
assert len(leagues["data"]) > 0
# Fetch single league
league_id = leagues["data"][0]["id"]
league = client.get_league(league_id)
assert league["id"] == league_idSecurity Best Practices
API Key Management
- Never commit keys to version control
- Use environment variables for all secrets
- Rotate keys regularly (every 90 days)
- Use different keys for dev/staging/production
- Revoke compromised keys immediately
Request Signing
Always verify webhook signatures:
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected_signature = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected_signature}"}", signature)Input Validation
def validate_league_id(league_id: str) -> bool:
if not league_id or not league_id.startswith("league_"):
raise ValueError("Invalid league ID format")
if len(league_id) > 100:
raise ValueError("League ID too long")
return TrueTroubleshooting
Common Issues
Invalid API Key (401)
Solutions:
- Verify API key is correct
- Check header name is
X-API-Key(case-sensitive) - Ensure no whitespace in key
- Verify correct environment (sandbox vs production)
Rate Limit Exceeded (429)
Solutions:
- Implement exponential backoff
- Check
Retry-Afterheader - Cache frequently accessed data
- Upgrade to higher tier plan
Webhook Not Receiving Events
Solutions:
- Verify URL is publicly accessible
- Check signature verification
- Ensure endpoint returns 200 OK within 5 seconds
- Check webhook logs in dashboard
- Test with webhook.site
Debug Mode
import logging
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
client = AltSportsLeaguesClient(api_key=API_KEY)
leagues = client.get_leagues(sport="mma")Support Resources
- Technical Support: api-support@altsportsleagues.ai
- API Status: https://status.altsportsleagues.ai (opens in a new tab)
- Documentation: https://docs.altsportsleagues.ai (opens in a new tab)
- GitHub Issues: https://github.com/altsportsleagues/api-issues (opens in a new tab)
For complete API reference, see API Documentation