Warning
This project is under active development. Features and APIs may change.
An AI-powered assistant and comprehensive toolkit for finding available Padel court slots on Playtomic. The project features a LangGraph-based agent that enables natural language interaction for slot search, along with a powerful Python client library and CLI.
- π€ AI Agent (LangGraph): Natural language interface to find the perfect slot
- π Python Client Library: Class-based APIclient with full type hints
- π» Command-Line Interface: Direct CLI for quick searches
- π Advanced Filtering:
- Filter by club (slug or name)
- Filter by court type (SINGLE or DOUBLE)
- Filter by time range with timezone support
- Filter by slot duration (60, 90, 120 minutes)
- π‘οΈ Robust Error Handling: Custom exceptions for better debugging
- β Fully Tested: Comprehensive test suite with 65%+ coverage
git clone https://github.com/DavidSchmidt00/playtomic-agent.git
cd playtomic-agent
pip install -e .pip install -e ".[dev]"The application uses environment variables for configuration. Create a .env file based on .env.example:
cp .env.example .env# Google Gemini API Keys (get from https://aistudio.google.com/)
GEMINI_API_KEY_FREE=your_free_tier_key
GEMINI_API_KEY_PAID=your_paid_tier_key
# Optional Configuration
DEFAULT_TIMEZONE=Europe/Berlin
DEFAULT_MODEL=gemini-3-flash-preview
PLAYTOMIC_API_BASE_URL=https://api.playtomic.io/v1cd src/playtomic_agent
langgraph devThen interact through the LangGraph Studio UI or API.
from playtomic_agent.agent import playtomic_agent
# Stream agent responses
for chunk in playtomic_agent.stream(
{"messages": [{"role": "user", "content":
"Find a 90-minute double court slot at lemon-padel-club "
"tomorrow between 18:00 and 20:00"
}]},
stream_mode="updates",
):
for step, data in chunk.items():
print(f"{step}: {data['messages'][-1].content}")The modern, class-based client provides full control:
from playtomic_agent.client.api import PlaytomicClient
# Use as context manager for automatic cleanup
with PlaytomicClient() as client:
# Find available slots
slots = client.find_slots(
club_slug="lemon-padel-club",
date="2026-02-15",
court_type="DOUBLE",
start_time="18:00",
end_time="20:00",
timezone="Europe/Berlin",
duration=90
)
for slot in slots:
print(f"{slot.court_name}: {slot.time} - {slot.price}")
print(f"Book: {slot.get_link()}")from playtomic_agent.client.api import PlaytomicClient
with PlaytomicClient() as client:
# 1. Get club information
club = client.get_club(slug="lemon-padel-club")
print(f"Club: {club.name} ({len(club.courts)} courts)")
# 2. Get all available slots
available_slots = client.get_available_slots(
club,
date="2026-02-15",
start_time="18:00", # UTC
end_time="20:00"
)
# 3. Filter manually
filtered = client.filter_slots(
club,
available_slots,
court_type="DOUBLE",
duration=90
)Quick searches from the terminal:
# Find all slots for today
playtomic-agent --club-slug lemon-padel-club
# Find 90-minute double court slots tomorrow
playtomic-agent \
--club-slug lemon-padel-club \
--date 2026-02-15 \
--court-type DOUBLE \
--duration 90 \
--start-time 18:00 \
--end-time 20:00 \
--timezone Europe/Berlin
# Output as JSON
playtomic-agent --club-slug lemon-padel-club --json
# Verbose mode
playtomic-agent --club-slug lemon-padel-club -vplaytomic-agent/
βββ src/playtomic_agent/ # Main package
β βββ agent.py # LangGraph AI agent
β βββ tools.py # LangChain tools for agent
β βββ config.py # Configuration management
β βββ models.py # Pydantic data models
β βββ client/ # API client package
β β βββ api.py # PlaytomicClient class
β β βββ exceptions.py # Custom exceptions
β β βββ utils.py # Utility functions
β β βββ cli.py # CLI implementation
β βββ langgraph.json # LangGraph configuration
βββ tests/ # Comprehensive test suite
β βββ conftest.py # Pytest fixtures
β βββ test_models.py # Model tests
β βββ test_exceptions.py # Exception tests
β βββ test_client.py # Client tests
βββ pyproject.toml # Modern Python packaging
βββ .env # Environment configuration
# Run all tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=src/playtomic_agent --cov-report=html
# Run specific test file
pytest tests/test_client.py -v# Format code
black src/ tests/
# Lint
ruff check src/ tests/
# Type checking
mypy src/Main client class for interacting with the Playtomic API.
Methods:
get_club(slug=None, name=None)- Fetch club informationget_available_slots(club, date, start_time=None, end_time=None)- Get available slotsfilter_slots(club, available_slots, court_type=None, duration=None)- Filter slotsfind_slots(club_slug, date, **filters)- Convenience method combining all steps
Exceptions:
ClubNotFoundError- Club not foundMultipleClubsFoundError- Multiple clubs match identifierAPIError- API request failedValidationError- Invalid input parameters
All models are Pydantic models with full validation:
Club- Represents a Playtomic clubCourt- Represents a court (single/double)Slot- Represents an available time slot
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Install development dependencies:
pip install -e ".[dev]" - Write tests for new features
- Ensure all tests pass:
pytest tests/ - Format code:
black src/ tests/ - Submit a pull request
MIT
- Built with LangGraph for AI agent orchestration
- Powered by Google Gemini for natural language understanding
- Uses the Playtomic API for court availability data