Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx
- Added `CLP` and `PEN` currency code support. See [related changelog](https://developer.paddle.com/changelog/2026/clp-pen-currencies?utm_source=dx&utm_medium=paddle-python-sdk)
- Added `rotatable` to api_key events. See [related changelog](https://developer.paddle.com/changelog/2026/aws-secrets-manager-rotation?utm_source=dx&utm_medium=paddle-python-sdk)
- Added `balance_movement_date` and `balance_movement_type` filters for payout reconciliation reports. See [related changelog](https://developer.paddle.com/changelog/2026/payout-reconciliation-report-filters?utm_source=dx&utm_medium=paddle-python-sdk)
- Added support for subscription history. See [related changelog](https://developer.paddle.com/changelog/2026/subscription-history?utm_source=dx&utm_medium=paddle-python-sdk)
- `Client.subscriptions.list_history`
- Added `type` to subscription `discount`
- Added `consent_requirements` to subscriptions
- Added `next_billed_at` filter to list subscriptions operation
- Added `checkout_domain.read`, `checkout_domain.write`, `client_token.read`, `client_token.write`, `metrics.read`, and `subscription_history.read` to `ApiKeyPermission` (permissions on `api_key.*` events)

### Changed

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations
from typing import Any

from paddle_billing.Entities.Collections.Collection import Collection
from paddle_billing.Entities.Collections.Paginator import Paginator
from paddle_billing.Entities.Subscriptions.History.SubscriptionHistory import SubscriptionHistory


class SubscriptionHistoryCollection(Collection[SubscriptionHistory]):
@classmethod
def from_list(
cls, items_data: list[dict[str, Any]], paginator: Paginator | None = None
) -> SubscriptionHistoryCollection:
items: list[SubscriptionHistory] = [SubscriptionHistory.from_dict(item) for item in items_data]

return SubscriptionHistoryCollection(items, paginator)
1 change: 1 addition & 0 deletions paddle_billing/Entities/Collections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from paddle_billing.Entities.Collections.SimulationRunEventCollection import SimulationRunEventCollection
from paddle_billing.Entities.Collections.SimulationTypeCollection import SimulationTypeCollection
from paddle_billing.Entities.Collections.SubscriptionCollection import SubscriptionCollection
from paddle_billing.Entities.Collections.SubscriptionHistoryCollection import SubscriptionHistoryCollection
from paddle_billing.Entities.Collections.SubscriptionPreviewCollection import SubscriptionPreviewCollection
from paddle_billing.Entities.Collections.TransactionCollection import TransactionCollection
from paddle_billing.Entities.Collections.TransactionPreviewCollection import TransactionPreviewCollection
Expand Down
14 changes: 14 additions & 0 deletions paddle_billing/Entities/Shared/ActionSource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class ActionSource(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
System: "ActionSource" = "system"
Api: "ActionSource" = "api"
Dashboard: "ActionSource" = "dashboard"
CustomerPortal: "ActionSource" = "customer_portal"
SupportBot: "ActionSource" = "support_bot"
Retain: "ActionSource" = "retain"
Checkout: "ActionSource" = "checkout"
ExternalProvider: "ActionSource" = "external_provider"
PaddleClassic: "ActionSource" = "paddle_classic"
Unknown: "ActionSource" = "unknown"
18 changes: 18 additions & 0 deletions paddle_billing/Entities/Shared/Actor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any

from paddle_billing.Entities.Shared.ActorType import ActorType


@dataclass
class Actor:
type: ActorType
id: str | None

@staticmethod
def from_dict(data: dict[str, Any]) -> Actor:
return Actor(
type=ActorType(data["type"]),
id=data.get("id"),
)
10 changes: 10 additions & 0 deletions paddle_billing/Entities/Shared/ActorType.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class ActorType(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Customer: "ActorType" = "customer"
User: "ActorType" = "user"
ApiKey: "ActorType" = "api_key"
PaddleStaff: "ActorType" = "paddle_staff"
Publisher: "ActorType" = "publisher"
System: "ActorType" = "system"
3 changes: 3 additions & 0 deletions paddle_billing/Entities/Shared/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from paddle_billing.Entities.Shared.Action import Action
from paddle_billing.Entities.Shared.ActionSource import ActionSource
from paddle_billing.Entities.Shared.Actor import Actor
from paddle_billing.Entities.Shared.ActorType import ActorType
from paddle_billing.Entities.Shared.AddressPreview import AddressPreview
from paddle_billing.Entities.Shared.AdjustmentActionType import AdjustmentActionType
from paddle_billing.Entities.Shared.AdjustmentItemTotals import AdjustmentItemTotals
Expand Down
6 changes: 6 additions & 0 deletions paddle_billing/Entities/Subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
)

from paddle_billing.Entities.Subscriptions import (
SubscriptionConsentRequirement,
SubscriptionDiscount,
SubscriptionItem,
SubscriptionManagementUrls,
Expand Down Expand Up @@ -51,6 +52,7 @@ class Subscription(Entity):
items: list[SubscriptionItem]
next_transaction: SubscriptionNextTransaction | None
recurring_transaction_details: TransactionDetailsPreview | None
consent_requirements: list[SubscriptionConsentRequirement]
import_meta: ImportMeta | None = None
custom_data: CustomData | None = None

Expand Down Expand Up @@ -98,4 +100,8 @@ def from_dict(data: dict[str, Any]) -> Subscription:
if data.get("recurring_transaction_details")
else None
),
consent_requirements=[
SubscriptionConsentRequirement.from_dict(consent_requirement)
for consent_requirement in data.get("consent_requirements", [])
],
)
6 changes: 6 additions & 0 deletions paddle_billing/Entities/SubscriptionPreview.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from paddle_billing.Entities.Shared.TransactionDetailsPreview import TransactionDetailsPreview

from paddle_billing.Entities.Subscriptions import (
SubscriptionConsentRequirement,
SubscriptionDiscount,
SubscriptionItem,
SubscriptionManagementUrls,
Expand Down Expand Up @@ -54,6 +55,7 @@ class SubscriptionPreview(Entity):
next_transaction: SubscriptionNextTransaction | None
recurring_transaction_details: TransactionDetailsPreview | None
update_summary: SubscriptionPreviewSubscriptionUpdateSummary | None
consent_requirements: list[SubscriptionConsentRequirement]
import_meta: ImportMeta | None

@staticmethod
Expand Down Expand Up @@ -108,5 +110,9 @@ def from_dict(data: dict[str, Any]) -> SubscriptionPreview:
if data.get("update_summary")
else None
),
consent_requirements=[
SubscriptionConsentRequirement.from_dict(consent_requirement)
for consent_requirement in data.get("consent_requirements", [])
],
import_meta=ImportMeta.from_dict(data["import_meta"]) if data.get("import_meta") else None,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any

from paddle_billing.Entities.Entity import Entity
from paddle_billing.Entities.Shared import ActionSource, Actor

from paddle_billing.Entities.Subscriptions.History.SubscriptionHistoryDetail import (
SubscriptionHistoryDetail,
SubscriptionHistoryDetailUnion,
)
from paddle_billing.Entities.Subscriptions.History.SubscriptionHistoryReason import SubscriptionHistoryReason


@dataclass
class SubscriptionHistory(Entity):
id: str
group_id: str
subscription_id: str
occurred_at: datetime
source: ActionSource
actor: Actor
reason: SubscriptionHistoryReason | None
detail: SubscriptionHistoryDetailUnion

@staticmethod
def from_dict(data: dict[str, Any]) -> SubscriptionHistory:
return SubscriptionHistory(
id=data["id"],
group_id=data["group_id"],
subscription_id=data["subscription_id"],
occurred_at=datetime.fromisoformat(data["occurred_at"]),
source=ActionSource(data["source"]),
actor=Actor.from_dict(data["actor"]),
reason=SubscriptionHistoryReason(data["reason"]) if data.get("reason") else None,
detail=SubscriptionHistoryDetail.from_dict(data["detail"]),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class SubscriptionHistoryAction(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
SubscriptionActivated: "SubscriptionHistoryAction" = "subscription_activated"
SubscriptionAddressUpdated: "SubscriptionHistoryAction" = "subscription_address_updated"
SubscriptionBillingCycleUpdated: "SubscriptionHistoryAction" = "subscription_billing_cycle_updated"
SubscriptionBillingDateUpdated: "SubscriptionHistoryAction" = "subscription_billing_date_updated"
SubscriptionBillingDetailsUpdated: "SubscriptionHistoryAction" = "subscription_billing_details_updated"
SubscriptionBusinessAdded: "SubscriptionHistoryAction" = "subscription_business_added"
SubscriptionBusinessRemoved: "SubscriptionHistoryAction" = "subscription_business_removed"
SubscriptionBusinessUpdated: "SubscriptionHistoryAction" = "subscription_business_updated"
SubscriptionCanceled: "SubscriptionHistoryAction" = "subscription_canceled"
SubscriptionCollectionModeUpdated: "SubscriptionHistoryAction" = "subscription_collection_mode_updated"
SubscriptionConsentRequirementGranted: "SubscriptionHistoryAction" = "subscription_consent_requirement_granted"
SubscriptionCreated: "SubscriptionHistoryAction" = "subscription_created"
SubscriptionCurrencyUpdated: "SubscriptionHistoryAction" = "subscription_currency_updated"
SubscriptionCustomDataUpdated: "SubscriptionHistoryAction" = "subscription_custom_data_updated"
SubscriptionCustomerUpdated: "SubscriptionHistoryAction" = "subscription_customer_updated"
SubscriptionDiscountAdded: "SubscriptionHistoryAction" = "subscription_discount_added"
SubscriptionDiscountExpired: "SubscriptionHistoryAction" = "subscription_discount_expired"
SubscriptionDiscountRemoved: "SubscriptionHistoryAction" = "subscription_discount_removed"
SubscriptionItemAdded: "SubscriptionHistoryAction" = "subscription_item_added"
SubscriptionItemQuantityUpdated: "SubscriptionHistoryAction" = "subscription_item_quantity_updated"
SubscriptionItemRemoved: "SubscriptionHistoryAction" = "subscription_item_removed"
SubscriptionOneOffChargeApplied: "SubscriptionHistoryAction" = "subscription_one_off_charge_applied"
SubscriptionPastDue: "SubscriptionHistoryAction" = "subscription_past_due"
SubscriptionPaused: "SubscriptionHistoryAction" = "subscription_paused"
SubscriptionPaymentAttempted: "SubscriptionHistoryAction" = "subscription_payment_attempted"
SubscriptionPaymentMethodAdded: "SubscriptionHistoryAction" = "subscription_payment_method_added"
SubscriptionPaymentMethodRemoved: "SubscriptionHistoryAction" = "subscription_payment_method_removed"
SubscriptionPaymentMethodUpdated: "SubscriptionHistoryAction" = "subscription_payment_method_updated"
SubscriptionRenewed: "SubscriptionHistoryAction" = "subscription_renewed"
SubscriptionResumed: "SubscriptionHistoryAction" = "subscription_resumed"
SubscriptionScheduledChangeAdded: "SubscriptionHistoryAction" = "subscription_scheduled_change_added"
SubscriptionScheduledChangeRemoved: "SubscriptionHistoryAction" = "subscription_scheduled_change_removed"
SubscriptionScheduledChangeUpdated: "SubscriptionHistoryAction" = "subscription_scheduled_change_updated"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class SubscriptionHistoryCanceledEffectiveFrom(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Immediately: "SubscriptionHistoryCanceledEffectiveFrom" = "immediately"
NextBillingPeriod: "SubscriptionHistoryCanceledEffectiveFrom" = "next_billing_period"
Loading
Loading