Python client for the Fizzy API
Project description
Fizzy API Client
Python client for the Fizzy API.
Installation
pip install fizzy-api-client
Quick Start
from fizzy import FizzyClient
client = FizzyClient(
token="your-api-token",
account_slug="your-account-slug"
)
# List boards
boards = client.boards.list()
# Create a card
card = client.cards.create(
board_id="board-123",
title="My new card"
)
# List cards with filtering
cards = client.cards.list(
board_id="board-123",
tag_ids=["tag-1", "tag-2"],
status="open"
)
Authentication
Personal Access Token
The recommended authentication method for scripts and integrations:
from fizzy import FizzyClient
client = FizzyClient(
token="your-personal-access-token",
account_slug="your-account-slug"
)
Magic Link Session
For native applications that need user authentication:
from fizzy import FizzyClient
from fizzy.auth import request_magic_link, submit_magic_code
# Request a magic link
request_magic_link("user@example.com")
# User receives email with 6-character code
session_token = submit_magic_code("ABC123")
# Use the session token
client = FizzyClient(
session_token=session_token,
account_slug="your-account-slug"
)
Resources
Identity
# Get authenticated user info (list of accounts)
identity = client.identity.get()
for account in identity.accounts:
print(f"Account: {account.name} ({account.id})")
print(f" User: {account.user.name} - Role: {account.user.role}")
Boards
# List all boards
boards = client.boards.list()
# Get a specific board
board = client.boards.get("board-id")
# Create a board
board = client.boards.create(
name="My Board",
public_description="<p>Optional rich text description</p>"
)
# Update a board
board = client.boards.update("board-id", name="New Name")
# Delete a board
client.boards.delete("board-id")
Cards
# List cards with optional filters
cards = client.cards.list(
board_id="board-123", # Optional: filter by board
column_id="col-456", # Optional: filter by column
tag_ids=["tag-1"], # Optional: filter by tags
assignee_ids=["user-1"], # Optional: filter by assignees
status="open" # Optional: "open", "closed", "deferred"
)
# Get a specific card by number
card = client.cards.get(42) # Cards are accessed by number, not ID
# Create a card
card = client.cards.create(
board_id="board-123",
title="New Card",
description="<p>Rich text description</p>" # HTML supported
)
# Create a card with header image
card = client.cards.create(
board_id="board-123",
title="Card with Image",
image="/path/to/image.png" # File path or tuple (filename, file_obj, content_type)
)
# Update a card
card = client.cards.update(42, title="Updated Title")
# Update card with new header image
card = client.cards.update(42, image="/path/to/new-image.png")
# Delete card header image
client.cards.delete_image(42)
# Delete a card
client.cards.delete(42)
# Card operations
client.cards.close(42) # Close the card
client.cards.reopen(42) # Reopen a closed card
client.cards.postpone(42) # Move to "not now"
client.cards.triage(42, column_id="col-123") # Move to a column
client.cards.untriage(42) # Remove from triage
client.cards.toggle_tag(42, tag_title="Bug") # Toggle a tag on/off
client.cards.toggle_assignment(42, assignee_id="user-123") # Toggle assignment
client.cards.watch(42) # Start watching
client.cards.unwatch(42) # Stop watching
client.cards.gild(42) # Make a "golden ticket"
client.cards.ungild(42) # Remove golden status
Comments
# List comments on a card
comments = client.comments.list(42) # card_number
# Get a specific comment
comment = client.comments.get(42, "comment-id")
# Create a comment
comment = client.comments.create(
42, # card_number
body="<p>Hello, world!</p>" # HTML supported
)
# Update a comment
comment = client.comments.update(42, "comment-id", body="<p>Updated</p>")
# Delete a comment
client.comments.delete(42, "comment-id")
Reactions
# List reactions on a comment
reactions = client.reactions.list(42, "comment-id")
# Add a reaction
reaction = client.reactions.create(42, "comment-id", content="thumbs_up")
# Remove a reaction
client.reactions.delete(42, "comment-id", "reaction-id")
Steps (Checklist Items)
# List steps (retrieved from the card)
steps = client.steps.list(42) # card_number
# Get a specific step
step = client.steps.get(42, "step-id")
# Create a step
step = client.steps.create(42, content="Do this thing")
# Update a step (mark complete)
client.steps.update(42, "step-id", completed=True)
# Delete a step
client.steps.delete(42, "step-id")
Columns
# List columns on a board
columns = client.columns.list("board-id")
# Get a specific column
column = client.columns.get("board-id", "column-id")
# Create a column
column = client.columns.create("board-id", name="In Progress")
# Update a column
column = client.columns.update("board-id", "column-id", name="Done")
# Delete a column
client.columns.delete("board-id", "column-id")
Users
# List users in account
users = client.users.list()
# Get a specific user
user = client.users.get("user-id")
# Update a user (name or avatar)
user = client.users.update("user-id", name="New Name")
user = client.users.update("user-id", avatar="/path/to/avatar.png")
# Deactivate a user
client.users.delete("user-id")
Tags
# List all tags in account
tags = client.tags.list()
Notifications
# List notifications
notifications = client.notifications.list()
# Filter by read status
unread = client.notifications.list(read=False)
# Mark as read
client.notifications.mark_read("notification-id")
# Mark as unread
client.notifications.mark_unread("notification-id")
# Bulk mark as read
client.notifications.bulk_mark_read(["notif-1", "notif-2", "notif-3"])
File Uploads (Direct Uploads for Rich Text)
For embedding images in card descriptions or comments:
import hashlib
import base64
# Calculate MD5 checksum
with open("image.png", "rb") as f:
content = f.read()
checksum = base64.b64encode(hashlib.md5(content).digest()).decode()
# Create a direct upload
upload = client.uploads.create_direct_upload(
filename="image.png",
content_type="image/png",
byte_size=len(content),
checksum=checksum
)
# Upload to storage using the provided URL and headers
import httpx
httpx.put(
upload.upload_url,
content=content,
headers=upload.upload_headers
)
# Build an ActionText attachment tag
from fizzy import DirectUpload
tag = DirectUpload.build_attachment_tag(upload.signed_id)
# Use in card description or comment
client.cards.update(42, description=f"<p>Check this out: {tag}</p>")
client.comments.create(42, body=f"<p>Here's an image: {tag}</p>")
Pagination
# Auto-pagination iterator
for card in client.cards.list_all(board_id="board-123"):
print(card.title)
# Manual pagination
page = client.cards.list_paginated(board_id="board-123")
while page.has_next:
for card in page.items:
print(card.title)
page = page.next_page()
Async Usage
from fizzy import AsyncFizzyClient
import asyncio
async def main():
async with AsyncFizzyClient(
token="your-token",
account_slug="your-account-slug"
) as client:
# All methods are async
boards = await client.boards.list()
# Async iteration
async for card in client.cards.list_all():
print(card.title)
asyncio.run(main())
Error Handling
from fizzy.exceptions import (
FizzyError, # Base exception
AuthenticationError, # 401
ForbiddenError, # 403
NotFoundError, # 404
BadRequestError, # 400
RateLimitError, # 429
ServerError, # 5xx
)
try:
card = client.cards.get(99999)
except NotFoundError as e:
print(f"Card not found: {e.message}")
except BadRequestError as e:
print(f"Bad request: {e.message}")
except FizzyError as e:
print(f"API error: {e.status_code} - {e.message}")
Caching
ETag caching is enabled by default for GET requests:
# First request stores the ETag
card = client.cards.get(123)
# Subsequent requests use If-None-Match header
# Returns cached response if server returns 304
card = client.cards.get(123)
# Disable caching
client = FizzyClient(
token="...",
account_slug="...",
cache=False
)
Configuration
client = FizzyClient(
token="your-token",
account_slug="your-account-slug",
base_url="https://app.fizzy.do", # Default
cache=True, # Enable ETag caching (default)
timeout=30.0, # Request timeout in seconds
)
Development
# Clone the repository
git clone https://github.com/robzolkos/fizzy-client-python.git
cd fizzy-client-python
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=src/fizzy --cov-report=html
# Run linting
ruff check src tests
ruff format --check src tests
# Run type checking
mypy src
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fizzy_api_client-0.1.0.tar.gz.
File metadata
- Download URL: fizzy_api_client-0.1.0.tar.gz
- Upload date:
- Size: 22.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb6d2dff4e2811df01cc41e3a8d2f9f6575f8922245e13ddcb79d8041c1e48f5
|
|
| MD5 |
51b2e56ba59e413bccdbbfca4468587a
|
|
| BLAKE2b-256 |
684b13010a507b8a04323faf4d0f3b84f52381c29856616bcd4b34e1d50717fa
|
Provenance
The following attestation bundles were made for fizzy_api_client-0.1.0.tar.gz:
Publisher:
release.yml on robzolkos/fizzy-client-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzy_api_client-0.1.0.tar.gz -
Subject digest:
eb6d2dff4e2811df01cc41e3a8d2f9f6575f8922245e13ddcb79d8041c1e48f5 - Sigstore transparency entry: 787737530
- Sigstore integration time:
-
Permalink:
robzolkos/fizzy-client-python@3b63a8bad9dd07ca76da3e3e9641df9d7a607d34 -
Branch / Tag:
refs/tags/v.0.1.0 - Owner: https://github.com/robzolkos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3b63a8bad9dd07ca76da3e3e9641df9d7a607d34 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzy_api_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fizzy_api_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28b1a73cf5efa948f7efebfb9972ae3b6e19091212fb684a6828d540ae2cc4ab
|
|
| MD5 |
cfc4e2d2159c2a3427f0e472fe7003c2
|
|
| BLAKE2b-256 |
4e2a6b40ab53136aedd1f854ae0aee7e5a8fd9cabbd90ea21d7c5fa141106529
|
Provenance
The following attestation bundles were made for fizzy_api_client-0.1.0-py3-none-any.whl:
Publisher:
release.yml on robzolkos/fizzy-client-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzy_api_client-0.1.0-py3-none-any.whl -
Subject digest:
28b1a73cf5efa948f7efebfb9972ae3b6e19091212fb684a6828d540ae2cc4ab - Sigstore transparency entry: 787737533
- Sigstore integration time:
-
Permalink:
robzolkos/fizzy-client-python@3b63a8bad9dd07ca76da3e3e9641df9d7a607d34 -
Branch / Tag:
refs/tags/v.0.1.0 - Owner: https://github.com/robzolkos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3b63a8bad9dd07ca76da3e3e9641df9d7a607d34 -
Trigger Event:
push
-
Statement type: