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)
- π§ User Profile (Memory): Remembers your preferences (preferred club, court type, etc.) across sessions
- π‘οΈ Robust Error Handling: Custom exceptions for better debugging
git clone https://github.com/DavidSchmidt00/playtomic-agent.git
cd playtomic-agent
pip install -e .pip install -e ".[dev]"The application reads configuration from environment variables (or a .env file in the project root). Start from the provided template:
cp .env.example .env| Variable | When required | Description |
|---|---|---|
GEMINI_API_KEY |
LLM_PROVIDER=gemini (default) |
Google Gemini API key β get one at aistudio.google.com |
NVIDIA_API_KEY |
LLM_PROVIDER=nvidia |
NVIDIA API key (starts with nvapi-) |
WHATSAPP_PHONE_NUMBER |
Running whatsapp-agent |
Phone number with country code (e.g. +491729975477), used for pairing-code login. Without it the agent cannot pair on first run. |
| Variable | Default | Description |
|---|---|---|
LLM_PROVIDER |
gemini |
LLM backend: gemini or nvidia |
DEFAULT_MODEL |
gemini-3.0-flash-preview / deepseek-ai/deepseek-v3.1-terminus |
Override the model for the selected provider. Provider defaults are used when unset. |
DEFAULT_TIMEZONE |
Europe/Berlin |
Timezone used when the user's timezone is unknown |
PLAYTOMIC_API_BASE_URL |
https://api.playtomic.io/v1 |
Playtomic REST API base URL |
LOG_LEVEL |
INFO |
Python logging level (DEBUG, INFO, WARNING, ERROR) |
WHATSAPP_SESSION_DB |
data/whatsapp_session.db |
Path to the SQLite file where neonize stores the WhatsApp session |
WHATSAPP_STORAGE_PATH |
data/whatsapp_users.json |
Path to the JSON file storing per-user WhatsApp state and history |
WHATSAPP_DEVICE_OS |
Chrome |
Device OS name reported to WhatsApp (avoids the default Neonize fingerprint) |
WHATSAPP_DEVICE_PLATFORM |
CHROME |
DeviceProps.PlatformType reported to WhatsApp. Valid values: CHROME, FIREFOX, SAFARI, EDGE, DESKTOP, IOS_PHONE, ANDROID_PHONE |
WHATSAPP_SEND_DELAY_WPM |
400.0 |
Simulated typing speed (words/minute) added before sending a reply. Set to 0 to disable. |
cd 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
)The CLI supports two main modes: search and slots.
Find clubs by location (using geocoding) or by name.
# Search by Location
playtomic-cli search --location "Berlin"
# Search by Name
playtomic-cli search --name "Lemon Padel"Find slots for a specific club.
# Find all slots for today
playtomic-cli slots --club-slug lemon-padel-club
# Find 90-minute double court slots tomorrow
playtomic-cli slots \
--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-cli slots --club-slug lemon-padel-club --jsonThe agent can remember your preferences across sessions using Browser Local Storage.
Supported preferences:
- Preferred Club: Your go-to padel club
- City: Your default location for club searches
- Court Type: SINGLE or DOUBLE
- Duration: Preferred slot duration (e.g., 90 minutes)
- Preferred Time: Your usual play time (e.g., "evenings")
How it works:
- When you search, the agent may suggest saving your preferences.
- A confirmation prompt appears in the chat β click "Save" or "No thanks".
- Saved preferences appear as pills above the chat box and are used automatically in future searches.
- You can remove individual preferences or clear all at any time.
A minimal, extensible web frontend is included to interact with the LangGraph-based Playtomic agent. The frontend is a small React app (Vite) that talks to a FastAPI endpoint exposed by the Python service. It provides a centered chat UI with Markdown rendering, a loading indicator, and a user profile card.
-
Start the Dev Container in VS Code or Cursor.
-
The Backend (FastAPI) and Frontend (React) servers will automatically start via VS Code Tasks.
-
Access the web app at http://localhost:8080 to use the chat interface.
If running outside the container:
- Install Python dependencies and start the API server:
pip install -e .
uvicorn playtomic_agent.api:app --host 0.0.0.0 --port 8082- Start the frontend (port 8080):
cd web
npm install
npm run dev -- --port 8080- Open your browser at http://localhost:8080 to use the chat interface.
Notes:
- The frontend displays tool execution status (e.g. "Searching for clubs...") and the final assistant reply. Internal reasoning details are hidden.
- Add API-related settings (e.g. GEMINI API keys) to
.envwhen using the agent for real runs.
For a deep dive into the project's internals, see the Developer Guide.
graph TD
User[User] -->|Chat| Frontend[React Web UI]
Frontend -->|Unidirectional Stream| Backend[Python API (FastAPI)]
Backend -->|Orchestrates| Agent[LangGraph Agent]
Agent -->|Uses| Tools[Tools]
Tools -->|Calls| PlaytomicAPI[Playtomic API]
Agent -->|Queries| LLM[Google Gemini]
The project is split into two main parts:
- Backend (
src/): Python application using LangChain/LangGraph and FastAPI. - Frontend (
web/): React application using Vite.
# 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