A Python SDK for interacting with the Bloom Growth API, providing easy access to users, meetings, todos, goals, scorecards, issues, and headlines.
✨ New in v0.21.0: Improved internal architecture with reusable mixins and enhanced bulk operation performance!
pip install bloomy-pythonfrom bloomy import Client
# Initialize the client with your API key
client = Client(api_key="your-api-key-here")
# Or use environment variable BG_API_KEY
client = Client()
# Or configure API key with username and password
from bloomy import Configuration
config = Configuration()
config.configure_api_key("username", "password", store_key=True)
client = Client()import asyncio
from bloomy import AsyncClient
async def main():
# Use async client for better performance
async with AsyncClient(api_key="your-api-key-here") as client:
user = await client.user.details()
meetings = await client.meeting.list()
print(f"Hello {user.name}, you have {len(meetings)} meetings")
asyncio.run(main())# Get current user details
user = client.user.details()
# Get user with direct reports and positions
user = client.user.details(user_id=123, include_all=True)
# Search users
results = client.user.search("john")
# List all users
users = client.user.list()# List meetings
meetings = client.meeting.list()
# Get meeting details
meeting = client.meeting.details(meeting_id=123)
# Create a meeting
new_meeting = client.meeting.create(
title="Weekly Team Meeting",
attendees=[456, 789]
)
# Delete a meeting
client.meeting.delete(meeting_id=123)
# Get multiple meetings by ID (batch read)
result = client.meeting.get_many([123, 456, 789])
for meeting in result.successful:
print(f"{meeting.name} - {meeting.meeting_date}")
# Handle any failed retrievals
for error in result.failed:
print(f"Failed to get meeting: {error.error}")# List todos for current user
todos = client.todo.list()
# Create a todo
new_todo = client.todo.create(
title="Complete project proposal",
meeting_id=123,
due_date="2024-12-31"
)
# Complete a todo
client.todo.complete(todo_id=456)
# Update a todo
client.todo.update(
todo_id=456,
title="Updated title",
due_date="2024-12-25"
)# List goals
goals = client.goal.list()
# Create a goal
new_goal = client.goal.create(
title="Increase sales by 20%",
meeting_id=123,
user_id=456
)
# Update goal status
client.goal.update(goal_id=789, status="on") # on, off, or complete
# Archive a goal
client.goal.archive(goal_id=789)# Get current week
week = client.scorecard.current_week()
# List scorecard items
scorecards = client.scorecard.list(meeting_id=123)
# Update a score
client.scorecard.score(measurable_id=456, score=95.5)# List issues
issues = client.issue.list()
# Create an issue
new_issue = client.issue.create(
meeting_id=123,
title="Server performance degradation"
)
# Solve an issue
client.issue.solve(issue_id=456)# List headlines
headlines = client.headline.list(meeting_id=123)
# Create a headline
new_headline = client.headline.create(
meeting_id=123,
title="Product launch successful",
notes="Exceeded targets by 15%"
)
# Update a headline
client.headline.update(headline_id=456, title="Updated headline")
# Delete a headline
client.headline.delete(headline_id=456)client.v2 is a new namespace that talks to Bloom Growth's GraphQL API
instead of the REST API client.v1 (and the top-level attributes above) use.
It shares the same client instance, the same API key, and covers the same
entities — users, meetings, issues, headlines, todos, goals, milestones, and
metrics — plus a few things v1 doesn't have, like milestones as their own
resource.
from bloomy import Client
client = Client(api_key="your-api-key-here")
# v1 (REST) — unchanged
meetings = client.meeting.list()
# v2 (GraphQL) — new
meeting = client.v2.meeting.details(meetings[0].id)
issues = client.v2.issue.list(meeting.id)
issue = client.v2.issue.create(meeting.id, "New issue", notes="Details")
client.v2.issue.solve(issue.id)
goal = client.v2.goal.create(meeting.id, "Ship v2")
client.v2.milestone.create(goal.id, "Draft spec", due_date="2026-01-01")
metric = client.v2.metric.create(meeting.id, "New Customers", goal=10)
client.v2.metric.set_score(metric.id, 12, "2026-09-21")v2 raises GraphQLError (a subclass of APIError) instead of a plain
APIError, and its models (bloomy.v2.models) are separate classes from the
v1 ones. See the v2 guide
for the full tour, including description/notes behavior, archive-vs-delete
semantics per entity, and metric score/week semantics.
The SDK supports multiple ways to provide your API key:
- Direct initialization: Pass the API key when creating the client
- Environment variable: Set
BG_API_KEYin your environment - Configuration file: Store the API key in
~/.bloomy/config.yaml - Dynamic configuration: Use username/password to fetch and store the API key
# Using configuration file
config = Configuration()
config.configure_api_key("username", "password", store_key=True)The SDK raises specific exceptions for different error scenarios:
from bloomy.exceptions import BloomyError, ConfigurationError, AuthenticationError, APIError
try:
client.user.details()
except AuthenticationError:
print("Invalid API key")
except APIError as e:
print(f"API error: {e.message}, Status: {e.status_code}")
except BloomyError as e:
print(f"General error: {e}")This SDK uses:
- uv for package management
- ruff for formatting and linting
- basedpyright for type checking
- pytest for testing
To set up the development environment:
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync --all-extras
# Run tests
uv run pytest
# Format code
uv run ruff format .
# Run linting
uv run ruff check . --fix
# Type checking
uv run basedpyright- Python 3.12+
- httpx
- pyyaml
- pydantic