Skip to content

Models

User

boostylib.models.user.User

Bases: BaseModel

Boosty user.

Source code in src/boostylib/models/user.py
class User(BaseModel):
    """Boosty user."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: int
    name: str = ""
    email: str | None = None
    avatar_url: str | None = Field(default=None, alias="avatarUrl")
    has_avatar: bool = Field(default=False, alias="hasAvatar")
    is_official: bool = Field(default=False, alias="isOfficial")

Blog

boostylib.models.blog.Blog

Bases: BaseModel

Boosty blog/channel info.

Source code in src/boostylib/models/blog.py
class Blog(BaseModel):
    """Boosty blog/channel info."""

    model_config = ConfigDict(frozen=True, populate_by_name=True)

    blog_url: str = Field(default="", alias="blogUrl")
    title: str = ""
    description: list[dict[str, Any]] | str = ""
    owner: User | None = None
    count: BlogCount = BlogCount()
    is_subscribed: bool = Field(default=False, alias="isSubscribed")
    is_owner: bool = Field(default=False, alias="isOwner")
    has_adult_content: bool = Field(default=False, alias="hasAdultContent")
    cover_url: str | None = Field(default=None, alias="coverUrl")
    currency: str = "RUB"

    @property
    def url(self) -> str:
        return self.blog_url

    @property
    def subscriber_count(self) -> int:
        return self.count.subscribers

    @property
    def post_count(self) -> int:
        return self.count.posts

Post

boostylib.models.post.Post

Bases: BaseModel

A Boosty blog post.

Source code in src/boostylib/models/post.py
class Post(BaseModel):
    """A Boosty blog post."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: str
    title: str = ""
    content: list[ContentBlock] = Field(default=[], alias="data")
    created_at: datetime | int | None = Field(default=None, alias="createdAt")
    updated_at: datetime | int | None = Field(default=None, alias="updatedAt")
    access_level: AccessLevel | None = None
    tags: list[PostTag] = []
    comments_count: int = 0
    is_published: bool = Field(default=True, alias="isPublished")
    price: int = 0
    int_id: int | None = Field(default=None, alias="intId")
    has_access: bool = Field(default=True, alias="hasAccess")
    donations: int = 0
    donators: dict[str, Any] | None = None

    @property
    def tag_names(self) -> list[str]:
        """Get tag titles as strings."""
        return [t.title for t in self.tags]

tag_names property

Get tag titles as strings.

ContentBlock

boostylib.models.post.ContentBlock

Bases: BaseModel

A single content block within a post.

Source code in src/boostylib/models/post.py
class ContentBlock(BaseModel):
    """A single content block within a post."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    type: ContentType
    content: str | None = None
    url: str | None = None
    signed_url: str | None = None
    modificator: str | None = None
    modifications: dict[str, Any] | None = None

AccessLevel

boostylib.models.post.AccessLevel

Bases: BaseModel

Post access level configuration.

Source code in src/boostylib/models/post.py
class AccessLevel(BaseModel):
    """Post access level configuration."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    level_id: str | None = None
    name: str = "Free"
    price: int = 0
    currency: str = "RUB"
    is_free: bool = True

PostCreateRequest

boostylib.models.post.PostCreateRequest

Bases: BaseModel

Request body for creating a post.

Source code in src/boostylib/models/post.py
class PostCreateRequest(BaseModel):
    """Request body for creating a post."""

    title: str
    content: list[ContentBlock]
    access_type: PostAccess = PostAccess.FREE
    access_level_id: str | None = None
    minimum_donation_amount: int | None = None
    minimum_donation_currency: str = "RUB"
    tags: list[str] = []
    teaser: str | None = None
    scheduled_at: datetime | None = None

SubscriptionLevel

boostylib.models.subscription.SubscriptionLevel

Bases: BaseModel

A subscription tier for a blog.

Source code in src/boostylib/models/subscription.py
class SubscriptionLevel(BaseModel):
    """A subscription tier for a blog."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: int
    name: str = ""
    price: int = 0
    currency: str = "RUB"
    is_free: bool = False
    owner_id: int | None = Field(default=None, alias="ownerId")
    is_archived: bool = Field(default=False, alias="isArchived")
    currency_prices: dict[str, float] = Field(default_factory=dict, alias="currencyPrices")

SubscriptionStatus

boostylib.models.subscription.SubscriptionStatus

Bases: BaseModel

Result of subscription verification.

Source code in src/boostylib/models/subscription.py
class SubscriptionStatus(BaseModel):
    """Result of subscription verification."""

    model_config = ConfigDict(frozen=True, populate_by_name=True)

    is_subscribed: bool
    level: SubscriptionLevel | None = None
    expires_at: datetime | None = None
    is_paid: bool = False
    price: int | None = None
    currency: str | None = None

UserSubscription

boostylib.models.subscription.UserSubscription

Bases: BaseModel

A user's subscription to a blog.

Source code in src/boostylib/models/subscription.py
class UserSubscription(BaseModel):
    """A user's subscription to a blog."""

    model_config = ConfigDict(frozen=True, populate_by_name=True)

    blog_url: str
    level: SubscriptionLevel
    is_paid: bool = False
    expires_at: datetime | None = None

Comment

boostylib.models.comment.Comment

Bases: BaseModel

A comment on a post.

Source code in src/boostylib/models/comment.py
class Comment(BaseModel):
    """A comment on a post."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: str
    int_id: int | None = Field(default=None, alias="intId")
    author: User
    content: str | list[dict[str, Any]] = ""
    created_at: datetime | int | None = Field(default=None, alias="createdAt")
    reply_to: str | int | None = Field(default=None, alias="replyId")

    @property
    def text(self) -> str:
        """Extract plain text from content (handles both string and block list)."""
        if isinstance(self.content, str):
            return self.content
        parts = []
        for block in self.content:
            if block.get("type") == "text" and block.get("content"):
                parts.append(block["content"])
        return " ".join(parts)

text property

Extract plain text from content (handles both string and block list).

MediaFile

boostylib.models.media.MediaFile

Bases: BaseModel

An uploaded media file.

Source code in src/boostylib/models/media.py
class MediaFile(BaseModel):
    """An uploaded media file."""

    model_config = ConfigDict(frozen=True, populate_by_name=True)

    id: str
    url: str
    signed_url: str | None = None
    filename: str | None = None
    size: int | None = None
    content_type: str | None = None
    width: int | None = None
    height: int | None = None
    duration: float | None = None

Target

boostylib.models.target.Target

Bases: BaseModel

A blog fundraising or subscriber goal.

Source code in src/boostylib/models/target.py
class Target(BaseModel):
    """A blog fundraising or subscriber goal."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: int
    description: str = ""
    target_sum: int = Field(default=0, alias="targetSum")
    current_sum: int = Field(default=0, alias="currentSum")
    target_type: TargetType = Field(default=TargetType.MONEY, alias="type")
    blog_url: str = Field(default="", alias="bloggerUrl")

Subscriber

boostylib.models.subscriber.Subscriber

Bases: BaseModel

A subscriber to a blog — includes email and payment history.

Source code in src/boostylib/models/subscriber.py
class Subscriber(BaseModel):
    """A subscriber to a blog — includes email and payment history."""

    model_config = ConfigDict(frozen=True, populate_by_name=True, extra="ignore")

    id: int
    name: str = ""
    email: str = ""
    avatar_url: str | None = Field(default=None, alias="avatarUrl")
    has_avatar: bool = Field(default=False, alias="hasAvatar")
    is_official: bool = Field(default=False, alias="isOfficial")
    level: SubscriptionLevel | None = None
    price: int = 0
    payments: float = 0.0
    status: str = "active"
    subscribed: bool = False
    on_time: int | None = Field(default=None, alias="onTime")
    off_time: int | None = Field(default=None, alias="offTime")
    is_black_listed: bool = Field(default=False, alias="isBlackListed")
    is_fee_paid: bool = Field(default=False, alias="isFeePaid")
    can_write: bool = Field(default=False, alias="canWrite")

    @property
    def is_active(self) -> bool:
        return self.status == "active" and self.subscribed

    @property
    def is_paid(self) -> bool:
        return self.price > 0

PaginatedResponse

boostylib.models.pagination.PaginatedResponse

Bases: BaseModel, Generic[T]

Paginated API response.

Parameters:

Name Type Description Default
data

List of items on this page.

required
cursor

Opaque cursor for the next page (None if last page).

required
is_last

Whether this is the last page.

required
total

Total number of items (if provided by API).

required
Source code in src/boostylib/models/pagination.py
class PaginatedResponse(BaseModel, Generic[T]):  # noqa: UP046
    """Paginated API response.

    Args:
        data: List of items on this page.
        cursor: Opaque cursor for the next page (None if last page).
        is_last: Whether this is the last page.
        total: Total number of items (if provided by API).
    """

    model_config = ConfigDict(frozen=True, populate_by_name=True)

    data: list[T]
    cursor: str | None = None
    is_last: bool = True
    total: int | None = None