Changelog
0.19.0 (2026-05-10)
⚠ BREAKING CHANGES
cancel_booking no longer accepts BookingV2 objects and cancel_booking_new no longer accepts Booking objects.
Code Refactoring
comprehensive code quality cleanup from WTF audit (#130 ) (2271881 )
0.18.0 (2026-05-10)
⚠ BREAKING CHANGES
TotalBodyWeight renamed to TotalBodyWater, total_body_weight field renamed to total_body_water, total_body_weight_details renamed to total_body_water_details, OutsideSchedulingWindowError now inherits from BookingError instead of OtfError
Documentation
complete documentation overhaul with MkDocs-Material (#127 ) (daef89e )
0.17.0 (2026-05-09)
Features
add diagnostic logging for silent failures and empty API responses (#119 ) (bc4e853 )
bookings: detect waitlisted V2 bookings via waitlist_position field (#125 ) (461b517 )
Bug Fixes
cancel_booking crash on BookingV2 and missing class_uuid in get_workout_from_booking (#124 ) (f525d1a )
0.16.0 (2026-04-28)
⚠ BREAKING CHANGES
removed deprecated flat methods on Otf class (e.g., otf.book_class()). Use the domain-scoped API instead (e.g., otf.bookings.book_class()).
Features
add field validators and relative descriptor properties to BodyCompositionData (0c1b489 )
add PII anonymization pipeline with real-time capture mode (#109 ) (c2c381e )
api.py, auth.py: add refresh callback functionality to handle token refresh events (e4dacc2 )
api.py: add exclude_checkedin parameter to get_bookings method to filter out checked-in bookings (d7fcf32 )
api.py: add filtering by day of week and start time for class retrieval (96d20e0 )
api.py: add home_studio_uuid parameter to Otf class for better user context management (f03b6a5 )
api.py: add hydrate method to Otf class to create instances from a dictionary (8577ad1 )
api.py: add logging and print statement when starting background token refresh task (12b6f9f )
api.py: add main function to initialize Otf instance using env vars (c1d9315 )
api.py: add methods to get booking by class and booking UUID for better booking management (6094072 )
api.py: add new exceptions for booking errors to improve error handling (6094072 )
api.py: add optional device_key parameter to hydrate method to allow more flexible instantiation (c5e2560 )
api.py: add print statement to debug background task for refreshing token (a8f04ac )
api.py: add retry logic to _get_performance_summary_raw to handle intermittent None responses (82e9fb0 )
api.py: add support for refresh_token and device_key in Otf class initialization (04c4294 )
api.py: add support for token-based authentication and background token refresh (554e968 )
api.py: add support for user object and refresh callback in Otf class (a081fe2 )
api.py: add user parameter to Otf class constructor to allow passing a user object (7508b09 )
api.py: enhance class booking and cancellation with additional checks and error handling (6094072 )
api.py: extend Api.create method to support token-based authentication (85185eb )
api: add class and coach rating functionality (1032df1 )
api: implement async context manager methods in Otf class to automatically handle session lifecycle (ed4f287 )
api: implement get_studios_by_geo as alias for search_studios_by_geo (ed4f287 )
auth.py, user.py: add has_cached_credentials method to check for cached credentials (ed4f287 )
auth.py: add check_token method to verify and optionally renew access tokens (30faeb6 )
auth.py: add class methods for creating OtfCognito instances from tokens and login credentials (80a64ac )
auth.py: add device key support to OtfCognito class for enhanced security (a938c06 )
auth.py: add koji_person_id field to IdClaimsData model to include custom identifier (0c1b489 )
auth.py: add logging for token refresh to improve debugging and monitoring (1192201 )
auth.py: add logging to track token refresh process (63c2199 )
auth.py: add logging when clearing device key to improve traceability (101f195 )
auth.py: add method to create User instance from an id token (554e968 )
auth.py: add methods to check and retrieve username from cache file (4647b55 )
auth.py: add model_config to OtfUser to allow arbitrary types in pydantic model (11d3869 )
auth.py: add OtfCognito class to handle device metadata and token renewal (9e9de81 )
auth.py: add property and setter for device_key with logging for security (1538fec )
auth.py: add validation for refresh_callback to ensure it is a callable function with one argument (15a4dd4 )
auth: add get_tokens method to OtfUser class to retrieve tokens (c520e39 )
base.py: add item getter methods to OtfBaseModel for flexible key access (0282e67 )
bookings.py: add book and cancel commands to manage class bookings (b0f9f70 )
bookings.py: add BookingStatusCli enum for CLI-friendly booking statuses (0282e67 )
bookings.py: add interactive booking cancellation feature to improve user experience (5095e6b )
bookings.py: add interactive booking options for studio UUIDs, date range, class type, day of week, and start time (96d20e0 )
bookings.py: integrate OtfClassTimeMixin into OtfClass for time-related properties (0282e67 )
bookings.py: update BookingList to include new class time columns (0282e67 )
bookings: add methods to BookingStatus and StudioStatus enums for case-insensitive lookups and listing all statuses (4647b55 )
bookings: add to_table method to BookingList for rich table representation (4647b55 )
cancel_booking: add new response model for cancel booking (195e4da )
classes_api: add class_type and exclude_cancelled filters to get_classes method (ffc1cee )
classes_api: add filtering by date range and limit to get_classes method (76a358a )
classes_api: integrate booking status to mark classes as booked (ffc1cee )
classes.py: add ClassType and ClassTypeCli enums for class type management (0282e67 )
classes.py: add DoW enum for day of week filtering and case-insensitive matching (96d20e0 )
classes.py: add OtfClassTimeMixin for time-related properties in OtfClass (0282e67 )
classes.py: enhance OtfClass with sidebar data and availability properties (0282e67 )
classes.py: update OtfClassList to include new class time columns (0282e67 )
classes: add class_name to sidebar_data in OtfClass (0c1b489 )
classes: add table representation for class list (195e4da )
cli: add bookings command to list booking data (3bf547b )
cli: add classes command to CLI for listing classes (76a358a )
cli: add exclude_cancelled option to list_bookings command (b1de127 )
cli: add interactive booking command to book classes interactively (b1de127 )
cli: add prompts module for user input and selection (b1de127 )
cli: add utility functions for CLI exception handling and async support (3bf547b )
cli: implement CLI structure with AsyncTyper and command handling (3bf547b )
deps: add httpx version 0.27.0 for HTTP requests (b7f8f91 )
examples: add class bookings example script to demonstrate API usage (292c987 )
examples: add favorite studio management to studio_examples.py (ed4f287 )
exceptions.py: add original_exception attribute to OtfRequestError for better error context (e3cb63a )
exceptions.py: introduce ConflictingBookingError to handle booking conflicts (ed4f287 )
filters.py: add filter_classes method to ClassFilter to encapsulate filtering logic and enhance reusability (ed4f287 )
lifetime_stats.py: add new model for lifetime statistics response (0c1b489 )
member_api.py: add book_class and cancel_booking methods to handle booking operations (b0f9f70 )
member_api: add exclude_cancelled parameter to filter out cancelled bookings (60366bc )
member_detail.py: add MemberReferrer class to handle member referrer data (1f8e2d2 )
models: add _columns method to BookingList for table headers (0c1b489 )
models: add attr_to_column_header method to OtfClass and Booking classes for dynamic column header mapping (2376c94 )
models: add BetterDumperMixin for enhanced Pydantic model dumping (812bf72 )
models: add BodyCompositionData model to handle body composition responses (0c1b489 )
models: add book_class response models to handle booking data (195e4da )
models: add BookClass and CancelBooking to response models (195e4da )
models: add new Pydantic models for handling booking and client data (195e4da )
models: add properties to Booking for id_val and sidebar_data (0c1b489 )
models: add Telemetry model to handle telemetry data (63feb5f )
models: start updating models to handle missing data, exclude data, remove unnecessary sub models (d671bc2 )
otf_api: introduce OtfSync class for synchronous API interactions (ed4f287 )
pyproject.toml: add CLI script entry point for otf_api (3bf547b )
pyproject.toml: add new development dependencies for testing and code quality (b55df47 )
pyproject.toml: add pint library to dependencies for unit conversion functionality (2569dbc )
pyproject.toml: add python-box and inflection dependencies to enhance functionality (06c2980 )
pyproject.toml: add readchar and humanize dependencies for enhanced CLI functionality (dd6ab5b )
pyproject.toml: add typer and pendulum dependencies for CLI support (06a11d6 )
pyproject.toml: update aiohttp from 3.8.6 to 3.10.5 to work with Python 3.11+ (fed9073 )
python_package.yml: add create-release job to automate GitHub release creation after publishing to PyPI (2b481b6 )
tox.ini: add pipx install poetry in commands_pre to ensure poetry is installed (eefb5b3 )
utils.py: enable environment variable support for username and password to facilitate automated authentication (ed4f287 )
Bug Fixes
api.py: add **kwargs to API request methods to allow additional parameters (308e9c5 )
api.py: add check for session attribute before attempting to close it (84faff4 )
api.py: add hasattr check for _refresh_task in shutdown method to prevent attribute error (264fc8a )
api.py: add synchronous member details retrieval to avoid async initialization issues (04c4294 )
api.py: allow multiple class types for class retrieval (96d20e0 )
api.py: change User method from load_from_disk to login for clarity (84faff4 )
api.py: clear cache after rating a class to ensure updated data is returned (2fb5b3c )
api.py: deprecate limit argument in get_performance_summaries to simplify API (2fb5b3c )
api.py: enhance error message to include provided authentication kwargs (ecae909 )
api.py: ensure distance does not exceed 250 miles in _get_studios_by_geo to adhere to API constraints (ed4f287 )
api.py: improve error handling by logging response text on exceptions (308e9c5 )
api.py: initialize _ref attribute to None to avoid potential attribute errors (82baf91 )
api.py: initialize aiohttp.ClientSession with authorization headers to ensure authenticated requests (d7fcf32 )
api.py: update type hints and docstrings for consistency and clarity (2fb5b3c )
api.py: wrap signal handling in try-except block to prevent crashes on unsupported platforms (b55df47 )
api: correct page size limit in search_studios_by_geo to 100 (ed4f287 )
api: update telemetry method to use performance_summary_id instead of class_history_uuid (a1ce303 )
auth.py: add check for existing device key before clearing to avoid unnecessary log entries (e131c66 )
auth.py: add token verification to ensure tokens are valid before creating User instance (0690fef )
auth.py: add type annotations and return types to check_token method for better clarity and type safety (80a64ac )
auth.py: change log level from debug to info for token refresh message (a8f04ac )
auth.py: change refresh_token method to return a boolean indicating success (a081fe2 )
auth.py: correct attribute name from device_metadata to device_key for token generation (2f9bc99 )
auth.py: ensure refresh callback is called after token refresh (e4dacc2 )
auth.py: ensure token properties return values from cognito if available (ed4f287 )
auth.py: handle TokenVerificationException during access token renewal (a938c06 )
auth.py: move background refresh task to OtfUser class to ensure token refresh logic is encapsulated within the user class (15a4dd4 )
auth.py: move token refresh log message to correct location and ensure save_to_disk is called only when tokens are refreshed (f23865e )
auth.py: remove optional parameters from load_from_disk method to ensure username and password are always provided for reauthentication (907f626 )
auth.py: remove redundant hasattr check before clearing device key (764a715 )
auth.py: update device_key property to handle None type values (2503728 )
auth: update type hints from Cognito to OtfCognito for consistency (ed4f287 )
body_composition_list.py: remove empty line to make linter happy (26f1a47 )
body_composition_list.py: update member_id type to accept both str and int (ed4f287 )
bookings.py: make description field optional in Studio model to handle cases where description might be missing (bba0d5e )
classes_api: correct variable name from res to classes_resp for clarity (ffc1cee )
classes.py: remove usage of Self type hint for compatibility with older Python versions (d08c643 )
classes.py: return DoW instead of string from day_of_week_enum (194f1ff )
classes: change "90 min" to "90 minutes" for consistency (0c1b489 )
cli: add help descriptions for book and cancel options (ce2bccc )
cli: add missing envvar for OPT_OUTPUT option in app.py (ce2bccc )
cli: correct columns method calls in bookings and classes (ce2bccc )
cliff.toml: add default value for commit_id to handle undefined cases (ab5cbdc )
cliff.toml: ensure commit_id is present before adding unreleased (9d2cca5 )
cli: remove unused kwargs in list_bookings and list_classes (ce2bccc )
cli: update command aliases to name in bookings and classes (ce2bccc )
correct import paths for User and Otf classes (0ffb313 )
dependencies: change aiohttp version to 3.8.* for better compatibility (9845822 )
enums.py: change EquipmentType and ChallengeType to use IntEnum for better integer handling (ed4f287 )
examples: correct instantiation of Otf class in examples to remove async creation method (3adcd6c )
exceptions: add specific exceptions for rating errors (1032df1 )
fix the thing i just broke, use .parent (7c44ac8 )
gen_ref_pages.py: skip files named version in documentation generation (4332db8 )
imports: update all references to User to OtfUser to match new class name (c520e39 )
mask strictness passes through non-PII primitive and structural values (#112 ) (b57c93b )
member_api: update sorting key to use starts_at_local instead of start_date_time (60366bc )
member_detail.py: allow for no homePhone (7568833 )
member_detail.py: correct member_address_uuid field to handle None values and unify alias handling (0c1b489 )
mixins: make address_line1 optional in AddressMixin for flexibility (ed4f287 )
models/base.py: change model_config extra from "forbid" to "allow" to permit additional fields (2c96d37 )
models: exclude sensitive fields from API responses for better security and privacy (4647b55 )
models: make created_by and updated_by fields optional (0c1b489 )
models: update init .py to include missing imports and reorder (c1d9315 )
models: update imports and all to reflect Telemetry changes (63feb5f )
pass the correct object to models to use in api calls (80ac6ef )
performance_summary_detail.py: exclude and hide ratable field due to inaccuracy in reflecting data from PerformanceSummaryEntry (e48b8b5 )
performance_summary_list.py: add type field to Class model (02d9a08 )
prompts.py: handle empty data list in prompt_select_from_table function (812bf72 )
prompts.py: highlight already booked classes in grey in selection table (96d20e0 )
pyproject.toml: correct typo in pytest configuration section header (062eb3d )
pyproject.toml: pin griffe < 1 to fix mkdocs build (06ad79d )
pyproject.toml: reorder dependencies alphabetically for better readability (b55df47 )
responses: update init .py to include missing imports and reorder (c1d9315 )
telemetry.py: add rowData fields to Telemetry model (74e72f4 )
telemetry.py: allow for no hr data in telemetry (823d57b )
telemetry.py: lowercase row_spm (d54beb4 )
tox.ini: add poetry install command to ensure dev dependencies are installed before running checks (3f6957f )
tox.ini: replace poetry with pipx in deps to manage dependencies (eefb5b3 )
update CLIENT_ID value from newest apk (f9f3495 )
use correct attribute for cache directory (eb1356b )
use correct attribute for cache directory (89f5f87 )
workout_examples.py: remove duplicate assignment of otf variable to prevent redundancy (1f8e2d2 )
api.py: cache _get_performance_summary_raw to improve performance by reducing redundant API calls (82e9fb0 )
api.py: use ThreadPoolExecutor for concurrent fetching of studio and performance summary details (2fb5b3c )
Documentation
api.py, auth.py: simplify and clarify the description of refresh_callback parameter in docstrings (afe8959 )
api.py: add docstring to Api.create method to describe new parameters and return type (85185eb )
api.py: update docstrings to include home_studio_uuid parameter and new methods (f03b6a5 )
auth_examples: remove outdated comments related to cache_device_data option (ed4f287 )
auth.py: update docstrings to reflect changes in token handling and device key usage (a938c06 )
auth: update all to reflect the renamed OtfUser class (c520e39 )
CONTRIBUTING.md: update reference from HISTORY.md to CHANGELOG.md (d6ca531 )
examples: add example for rating a class (1032df1 )
examples: update workout examples to reflect new API methods (ed4f287 )
index.md: fix include-markdown path to correctly reference usage.md (d456660 )
index.md: replace README.md include with detailed API client description and installation instructions (082e065 )
mkdocs.yml: rename 'History' to 'Changelog' for clarity (435da88 )
mkdocs.yml: update email contact (435da88 )
pyproject.toml: add documentation URL to project metadata (062eb3d )
README.md, pyproject.toml: update documentation link to stable version (0139146 )
README.md, usage.md: update class name from Api to Otf for accuracy (3adcd6c )
README.md: expand documentation with installation, usage, and examples (603df75 )
README.md: remove extra blank line before disclaimer (c52a8dd )
README.md: remove extra blank line before disclaimer (082e065 )
README.md: remove outdated information about future goals for API methods (4b82b38 )
README.md: replace usage include with overview section and exam… (de16962 )
README.md: replace usage include with overview section and examples link to provide better guidance on using the API (2d9390d )
remove installation guide from documentation and mkdocs navigation (0139146 )
rename history.md to changelog.md and update references (d6ca531 )
update example scripts to use Otf class instead of Api (0ffb313 )
workflows: correct typos in package download URLs in dev and release workflows (a60c055 )
Code Refactoring
codebase audit fixes — bugs, legacy removal, model cleanup (#115 ) (f5d587f )