Boards API¶
Complete reference for board and image management using the Repository pattern, covering board lifecycle operations, image upload/download, and organizational features. Key implementations include BoardRepository
for board management and BoardHandle
for per-board operations.
BoardRepository¶
Repository for managing boards and their lifecycle. Implements the Repository pattern to separate board operations from the main client interface.
Core Board Management Methods¶
list_boards()
- Retrieve All Boards¶
List all available boards with optional filtering.
Parameters:
- all
(bool): Include all boards regardless of visibility (default: True)
- include_uncategorized
(bool): Whether to include the special uncategorized board (default: False)
Returns:
- list[Board]
: List of Board objects with metadata and image counts
Example:
# Get all boards excluding uncategorized
boards = client.board_repo.list_boards()
# Include uncategorized board
all_boards = client.board_repo.list_boards(include_uncategorized=True)
# Find boards with images
active_boards = [b for b in boards if b.image_count > 0]
create_board()
- Create New Board¶
Create a new board and return its handle for immediate operations.
Parameters:
- name
(str): Display name for the board
- is_private
(bool): Whether the board should be private (default: False)
Returns:
- BoardHandle
: Handle for performing operations on the created board
Example:
# Create public board
renders_board = client.board_repo.create_board("Project Renders")
print(f"Created board: {renders_board.board_name}")
# Create private board
private_board = client.board_repo.create_board("Personal", is_private=True)
# Immediately upload to new board
image = private_board.upload_image("secret.png")
delete_board()
- Remove Board¶
Delete a board with optional image handling.
Parameters:
- board_id
(str): ID of the board to delete
- delete_images
(bool): If False, moves images to uncategorized; if True, deletes images (default: False)
Returns:
- bool
: True if deletion succeeded, False otherwise
Important Notes:
- Cannot delete the uncategorized board (board_id="none")
- By default, images are preserved by moving to uncategorized
- Use delete_images=True
to permanently remove images
Example:
# Safe delete - preserve images
success = client.board_repo.delete_board("old-project")
# Delete board and all its images (permanent)
client.board_repo.delete_board("temp-board", delete_images=True)
Board Lookup and Resolution Methods¶
get_board_by_id()
- Direct ID Lookup¶
Retrieve a specific board by its ID.
Parameters:
- board_id
(str): Unique board identifier
Returns:
- Board | None
: Board object if found, None if not found
get_boards_by_name()
- Name-Based Search¶
Find boards matching a specific name (may return multiple results).
Parameters:
- name
(str): Board name to search for
Returns:
- list[Board]
: List of matching boards (can be empty)
Handle Creation Methods¶
get_board_handle()
- Primary Handle Factory¶
Create a handle for performing operations on a specific board.
Parameters:
- board_id
(str | None): Board ID, use "none" or None for uncategorized
Returns:
- BoardHandle
: Handle for board operations
Example:
# Get handle for specific board
handle = client.board_repo.get_board_handle("my-board-123")
# Get uncategorized handle
uncategorized = client.board_repo.get_board_handle(None)
# or
uncategorized = client.board_repo.get_board_handle("none")
get_board_handle_by_name()
- Name-Based Handle¶
Get handle for first board matching the given name.
Parameters:
- name
(str): Board name to search for
Returns:
- BoardHandle | None
: Handle if board found, None otherwise
Uncategorized Board Helpers¶
get_uncategorized_board()
& get_uncategorized_handle()
¶
Convenience methods for accessing the special uncategorized board.
Example:
# Direct uncategorized access
uncat_board = client.board_repo.get_uncategorized_board()
uncat_handle = client.board_repo.get_uncategorized_handle()
# Upload to Assets tab (uncategorized)
image = uncat_handle.upload_image("reference.jpg")
update_board()
- Modify Board Properties¶
def update_board(
self,
board_id: str,
name: str | None = None,
is_private: bool | None = None
) -> Board | None:
Update board name and/or privacy settings.
Parameters:
- board_id
(str): ID of board to update
- name
(str | None): New name for the board (optional)
- is_private
(bool | None): New privacy setting (optional)
Returns:
- Board | None
: Updated board object if successful, None otherwise
Implementation details
- list_boards
: BoardRepository.list_boards()
- create_board
: BoardRepository.create_board()
- delete_board
: BoardRepository.delete_board()
- get_board_handle
: BoardRepository.get_board_handle()
- update_board
: BoardRepository.update_board()
Usage
# List boards (optionally include uncategorized)
boards = client.board_repo.list_boards(include_uncategorized=True)
for b in boards:
print(b.board_id, b.board_name, b.image_count)
# Create a board and get its handle
handle = client.board_repo.create_board("my_outputs")
print("Board:", handle.board_id, handle.board_name)
# Look up by name → first match, then get handle
h = client.board_repo.get_board_handle_by_name("my_outputs")
if h:
print("Found board", h.board_name)
BoardHandle¶
Perform image operations in the context of one board (including uncategorized).
class BoardHandle:
@property
def board_id(self) -> str: ... # "none" for uncategorized
@property
def board_name(self) -> str: ...
@property
def is_uncategorized(self) -> bool: ...
def refresh(self) -> None: ...
def list_images(
self,
offset: int = 0,
limit: int = 100,
order_by: str = "created_at",
order_dir: str = "DESC",
starred_first: bool = False,
search_term: str | None = None,
) -> list[str]: ...
def upload_image(
self,
file_path: str | Path,
is_intermediate: bool = False,
image_category: ImageCategory = ImageCategory.USER,
session_id: str | None = None,
) -> IvkImage: ...
def upload_image_data(
self,
image_data: bytes,
filename: str | None = None,
is_intermediate: bool = False,
image_category: ImageCategory = ImageCategory.USER,
session_id: str | None = None,
) -> IvkImage: ...
def download_image(self, image_name: str, full_resolution: bool = True) -> bytes: ...
def move_image_to(self, image_name: str, target_board_id: str) -> bool: ...
def remove_image(self, image_name: str) -> bool: ...
def delete_image(self, image_name: str) -> bool: ...
def star_image(self, image_name: str) -> bool: ...
def unstar_image(self, image_name: str) -> bool: ...
def get_image_count(self) -> int: ...
Important behaviors
- Uncategorized uploads: When uploading to uncategorized, the handle omits board_id so images land under the GUI’s Uncategorized. Passing "none" as board_id is intentionally avoided for uploads.
- list_images() supports ordering, pagination, and search. For uncategorized, the handle now uses the fast name list endpoint: /api/v1/boards/none/image_names
.
- download_image() checks membership first via list_images(); it raises if the image is not in this board.
- star_image() / unstar_image() toggle the starred flag.
- remove_image() moves an image off the current board to uncategorized. move_image_to() allows moving across boards.
- Returns: upload_image(_data) returns IvkImage; download_image returns bytes.
Implementation details
- upload_image
: BoardHandle.upload_image()
- upload_image_data
: BoardHandle.upload_image_data()
- list_images
: BoardHandle.list_images()
- download_image
: BoardHandle.download_image()
- Image operations: BoardHandle.move_image_to()
, BoardHandle.remove_image()
, BoardHandle.delete_image()
, BoardHandle.star_image()
, BoardHandle.unstar_image()
Examples
# Upload from file (to a named board)
handle = client.board_repo.create_board("assets")
img = handle.upload_image("data/images/sample.png")
print("Uploaded:", img.image_name)
# Upload from bytes to uncategorized (Assets tab)
uncat = client.board_repo.get_uncategorized_handle()
with open("data/images/sample.png", "rb") as f:
img2 = uncat.upload_image_data(f.read(), "sample.png")
print("Uploaded to Uncategorized:", img2.image_name)
# List, star, and download
names = handle.list_images(limit=20, starred_first=True)
if names:
handle.star_image(names[0])
data = handle.download_image(names[0], full_resolution=True)
with open(names[0], "wb") as out:
out.write(data)
Image Deletion¶
Single-image delete (via BoardHandle)
# Preconditions:
# - image_name is the server-side token (exact value returned by listings/DTO)
# - For uncategorized images, you can list names via: GET /api/v1/boards/none/image_names
uncat = client.board_repo.get_uncategorized_handle()
image_name = "0712249f-1047-4314-a338-d6807920f245.png" # example
# Delete and confirm via server contract
deleted = uncat.delete_image(image_name) # returns True only if server reports deletion
print("Deleted?", deleted)
BoardHandle.delete_image()
- Behavior: issues DELETE /api/v1/images/i/{image_name}
and parses the response JSON (deleted_images
list). Returns True
only if the specified image_name
appears in deleted_images
; otherwise False
. A 404 results in False
.
Resolving exact image_name
# If unsure about exact token (with/without extension), resolve robustly:
def resolve_exact_image_name(client, rough):
# Try DTO as-is
try:
if client._make_request("GET", f"/images/i/{rough}").status_code == 200:
return rough
except Exception:
pass
# Try stem
stem = rough.rsplit(".", 1)[0] if "." in rough else rough
try:
if client._make_request("GET", f"/images/i/{stem}").status_code == 200:
return stem
except Exception:
pass
# Fallback to uncategorized list (board_id="none")
try:
names = client._make_request("GET", "/boards/none/image_names").json()
if isinstance(names, list):
if rough in names: return rough
if stem in names: return stem
for n in names:
if n.startswith(stem): # prefix fallback
return n
except Exception:
pass
return None
Bulk deletion (raw API)
# Delete all uncategorized images:
resp = client._make_request("DELETE", "/images/uncategorized")
print(resp.json()) # -> {'deleted_images': [...], 'affected_boards': [...]}
# Delete a list of images:
payload = {"image_names": ["a.png", "b.png", "c.png"]}
resp = client._make_request("POST", "/images/delete", json=payload)
print(resp.json()) # -> {'deleted_images': [...], 'affected_boards': [...]}
DELETE /api/v1/images/i/{image_name}
(see InvokeAI images router)
- Bulk delete list: POST /api/v1/images/delete
(see InvokeAI images router)
- Delete all uncategorized: DELETE /api/v1/images/uncategorized
(see InvokeAI images router)
Error-handling pattern (optional)
# Raise on not found; raise on unknown failure; True on success; False otherwise.
def delete_image_strict(client, image_name: str) -> bool:
# Confirm existence
try:
exists = client._make_request("GET", f"/images/i/{image_name}").status_code == 200
except Exception as e:
raise RuntimeError(f"connection error verifying existence: {e}")
if not exists:
raise FileNotFoundError(f"image does not exist: {image_name}")
# Attempt deletion
try:
deleted = client.board_repo.get_uncategorized_handle().delete_image(image_name)
except Exception as e:
raise RuntimeError(f"delete failed: {e}")
if deleted:
return True
# Unknown failure if server didn’t report deletion and image still exists
try:
still_exists = client._make_request("GET", f"/images/i/{image_name}").status_code == 200
except Exception as e:
raise RuntimeError(f"connection error verifying deletion: {e}")
if still_exists:
raise RuntimeError("unknown error")
return False
Model
class Board(BaseModel):
board_id: str | None
board_name: str
description: str | None
created_at: datetime | None
updated_at: datetime | None
image_count: int
starred: bool | None
@classmethod
def uncategorized(cls, image_count: int = 0) -> "Board": ...
def is_uncategorized(self) -> bool: ...
Cross-references
- User guide: docs/user-guide/boards.md
- Examples: flux-image-to-image.py
- Raw API demos: api-demo-boards.py
, api-demo-upload-image.py