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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx&utm_medium=paddle-python-sdk) for information about changes to the Paddle Billing platform, the Paddle API, and other developer tools.

## 1.14.0 - 2026-03-30

### Added

- Added support for metrics endpoints. See [related changelog](https://developer.paddle.com/changelog/2026/metrics-api?utm_source=dx&utm_medium=paddle-python-sdk)
- `Client.metrics.get_monthly_recurring_revenue`
- `Client.metrics.get_monthly_recurring_revenue_change`
- `Client.metrics.get_active_subscribers`
- `Client.metrics.get_revenue`
- `Client.metrics.get_refunds`
- `Client.metrics.get_chargebacks`
- `Client.metrics.get_checkout_conversion`

## 1.13.1 - 2026-03-25

### Added
Expand Down
4 changes: 3 additions & 1 deletion paddle_billing/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from paddle_billing.Resources.SimulationRunEvents.SimulationRunEventsClient import SimulationRunEventsClient
from paddle_billing.Resources.SimulationTypes.SimulationTypesClient import SimulationTypesClient
from paddle_billing.Resources.Subscriptions.SubscriptionsClient import SubscriptionsClient
from paddle_billing.Resources.Metrics.MetricsClient import MetricsClient
from paddle_billing.Resources.Transactions.TransactionsClient import TransactionsClient


Expand Down Expand Up @@ -94,6 +95,7 @@ def __init__(
self.subscriptions = SubscriptionsClient(self)
self.transactions = TransactionsClient(self)
self.ip_addresses = IPAddressesClient(self)
self.metrics = MetricsClient(self)

@staticmethod
def null_logger() -> Logger:
Expand Down Expand Up @@ -200,7 +202,7 @@ def build_request_session(self) -> Session:
"Authorization": f"Bearer {self.__api_key}",
"Content-Type": "application/json",
"Paddle-Version": str(self.use_api_version),
"User-Agent": "PaddleSDK/python 1.13.1",
"User-Agent": "PaddleSDK/python 1.14.0",
}
)

Expand Down
27 changes: 27 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsActiveSubscribers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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.Metrics.MetricsCountDatapoint import MetricsCountDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval


@dataclass
class MetricsActiveSubscribers(Entity):
timeseries: list[MetricsCountDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsActiveSubscribers:
return MetricsActiveSubscribers(
timeseries=[MetricsCountDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
17 changes: 17 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsAmountDatapoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any


@dataclass
class MetricsAmountDatapoint:
timestamp: datetime
amount: str

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsAmountDatapoint:
return MetricsAmountDatapoint(
timestamp=datetime.fromisoformat(data["timestamp"]),
amount=data["amount"],
)
27 changes: 27 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsChargebacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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.Metrics.MetricsCountDatapoint import MetricsCountDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval


@dataclass
class MetricsChargebacks(Entity):
timeseries: list[MetricsCountDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsChargebacks:
return MetricsChargebacks(
timeseries=[MetricsCountDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
27 changes: 27 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsCheckoutConversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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.Metrics.MetricsCheckoutConversionDatapoint import MetricsCheckoutConversionDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval


@dataclass
class MetricsCheckoutConversion(Entity):
timeseries: list[MetricsCheckoutConversionDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsCheckoutConversion:
return MetricsCheckoutConversion(
timeseries=[MetricsCheckoutConversionDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any


@dataclass
class MetricsCheckoutConversionDatapoint:
timestamp: datetime
count: int
completed_count: int
rate: str

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsCheckoutConversionDatapoint:
return MetricsCheckoutConversionDatapoint(
timestamp=datetime.fromisoformat(data["timestamp"]),
count=data["count"],
completed_count=data["completed_count"],
rate=data["rate"],
)
17 changes: 17 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsCountDatapoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any


@dataclass
class MetricsCountDatapoint:
timestamp: datetime
count: int

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsCountDatapoint:
return MetricsCountDatapoint(
timestamp=datetime.fromisoformat(data["timestamp"]),
count=data["count"],
)
5 changes: 5 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsInterval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class MetricsInterval(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Day: "MetricsInterval" = "day"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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.Metrics.MetricsAmountDatapoint import MetricsAmountDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval
from paddle_billing.Entities.Shared import CurrencyCode


@dataclass
class MetricsMonthlyRecurringRevenue(Entity):
currency_code: CurrencyCode
timeseries: list[MetricsAmountDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsMonthlyRecurringRevenue:
return MetricsMonthlyRecurringRevenue(
currency_code=CurrencyCode(data["currency_code"]),
timeseries=[MetricsAmountDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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.Metrics.MetricsAmountDatapoint import MetricsAmountDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval
from paddle_billing.Entities.Shared import CurrencyCode


@dataclass
class MetricsMonthlyRecurringRevenueChange(Entity):
currency_code: CurrencyCode
timeseries: list[MetricsAmountDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsMonthlyRecurringRevenueChange:
return MetricsMonthlyRecurringRevenueChange(
currency_code=CurrencyCode(data["currency_code"]),
timeseries=[MetricsAmountDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
30 changes: 30 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsRefunds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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.Metrics.MetricsAmountDatapoint import MetricsAmountDatapoint
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval
from paddle_billing.Entities.Shared import CurrencyCode


@dataclass
class MetricsRefunds(Entity):
currency_code: CurrencyCode
timeseries: list[MetricsAmountDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsRefunds:
return MetricsRefunds(
currency_code=CurrencyCode(data["currency_code"]),
timeseries=[MetricsAmountDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
30 changes: 30 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsRevenue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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.Metrics.MetricsInterval import MetricsInterval
from paddle_billing.Entities.Metrics.MetricsRevenueDatapoint import MetricsRevenueDatapoint
from paddle_billing.Entities.Shared import CurrencyCode


@dataclass
class MetricsRevenue(Entity):
currency_code: CurrencyCode
timeseries: list[MetricsRevenueDatapoint]
starts_at: datetime
ends_at: datetime
interval: MetricsInterval
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsRevenue:
return MetricsRevenue(
currency_code=CurrencyCode(data["currency_code"]),
timeseries=[MetricsRevenueDatapoint.from_dict(dp) for dp in data.get("timeseries", [])],
starts_at=datetime.fromisoformat(data["starts_at"]),
ends_at=datetime.fromisoformat(data["ends_at"]),
interval=MetricsInterval(data["interval"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
19 changes: 19 additions & 0 deletions paddle_billing/Entities/Metrics/MetricsRevenueDatapoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any


@dataclass
class MetricsRevenueDatapoint:
timestamp: datetime
amount: str
count: int

@staticmethod
def from_dict(data: dict[str, Any]) -> MetricsRevenueDatapoint:
return MetricsRevenueDatapoint(
timestamp=datetime.fromisoformat(data["timestamp"]),
amount=data["amount"],
count=data["count"],
)
12 changes: 12 additions & 0 deletions paddle_billing/Entities/Metrics/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from paddle_billing.Entities.Metrics.MetricsInterval import MetricsInterval
from paddle_billing.Entities.Metrics.MetricsAmountDatapoint import MetricsAmountDatapoint
from paddle_billing.Entities.Metrics.MetricsCountDatapoint import MetricsCountDatapoint
from paddle_billing.Entities.Metrics.MetricsRevenueDatapoint import MetricsRevenueDatapoint
from paddle_billing.Entities.Metrics.MetricsCheckoutConversionDatapoint import MetricsCheckoutConversionDatapoint
from paddle_billing.Entities.Metrics.MetricsMonthlyRecurringRevenue import MetricsMonthlyRecurringRevenue
from paddle_billing.Entities.Metrics.MetricsMonthlyRecurringRevenueChange import MetricsMonthlyRecurringRevenueChange
from paddle_billing.Entities.Metrics.MetricsActiveSubscribers import MetricsActiveSubscribers
from paddle_billing.Entities.Metrics.MetricsRevenue import MetricsRevenue
from paddle_billing.Entities.Metrics.MetricsRefunds import MetricsRefunds
from paddle_billing.Entities.Metrics.MetricsChargebacks import MetricsChargebacks
from paddle_billing.Entities.Metrics.MetricsCheckoutConversion import MetricsCheckoutConversion
Loading
Loading