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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Check our main [developer changelog](https://developer.paddle.com/?utm_source=dx

### Added

- Added support for checkout domains. See [related changelog](https://developer.paddle.com/changelog/2026/checkout-domains-api?utm_source=dx&utm_medium=paddle-python-sdk)
- `Client.checkout_domains.list`
- `Client.checkout_domains.get`
- `Client.checkout_domains.delete`
- `Client.checkout_domains.verify_payment_method`
- Added support for `checkouts` report type. See [related changelog](https://developer.paddle.com/changelog/2026/checkouts-report?utm_source=dx&utm_medium=paddle-python-sdk)
- 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)
Expand Down
2 changes: 2 additions & 0 deletions paddle_billing/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from paddle_billing.Resources.Addresses.AddressesClient import AddressesClient
from paddle_billing.Resources.Adjustments.AdjustmentsClient import AdjustmentsClient
from paddle_billing.Resources.Businesses.BusinessesClient import BusinessesClient
from paddle_billing.Resources.CheckoutDomains.CheckoutDomainsClient import CheckoutDomainsClient
from paddle_billing.Resources.ClientTokens.ClientTokensClient import ClientTokensClient
from paddle_billing.Resources.Customers.CustomersClient import CustomersClient
from paddle_billing.Resources.CustomerPortalSessions.CustomerPortalSessionsClient import CustomerPortalSessionsClient
Expand Down Expand Up @@ -73,6 +74,7 @@ def __init__(
self.addresses = AddressesClient(self)
self.adjustments = AdjustmentsClient(self)
self.businesses = BusinessesClient(self)
self.checkout_domains = CheckoutDomainsClient(self)
self.client_tokens = ClientTokensClient(self)
self.customers = CustomersClient(self)
self.customer_portal_sessions = CustomerPortalSessionsClient(self)
Expand Down
30 changes: 30 additions & 0 deletions paddle_billing/Entities/CheckoutDomain.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.CheckoutDomains import CheckoutDomainPaymentMethodVerification, CheckoutDomainStatus


@dataclass
class CheckoutDomain(Entity):
id: str
domain: str
status: CheckoutDomainStatus
payment_method_verification: CheckoutDomainPaymentMethodVerification
created_at: datetime
updated_at: datetime

@staticmethod
def from_dict(data: dict[str, Any]) -> CheckoutDomain:
return CheckoutDomain(
id=data["id"],
domain=data["domain"],
status=CheckoutDomainStatus(data["status"]),
payment_method_verification=CheckoutDomainPaymentMethodVerification.from_dict(
data["payment_method_verification"]
),
created_at=datetime.fromisoformat(data["created_at"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
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.CheckoutDomains.CheckoutDomainPaymentMethodVerificationStatus import (
CheckoutDomainPaymentMethodVerificationStatus,
)


@dataclass
class CheckoutDomainApplePayVerification:
status: CheckoutDomainPaymentMethodVerificationStatus

@staticmethod
def from_dict(data: dict[str, Any]) -> CheckoutDomainApplePayVerification:
return CheckoutDomainApplePayVerification(
status=CheckoutDomainPaymentMethodVerificationStatus(data["status"]),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class CheckoutDomainPaymentMethod(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
ApplePay: "CheckoutDomainPaymentMethod" = "apple_pay"
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.CheckoutDomains.CheckoutDomainApplePayVerification import (
CheckoutDomainApplePayVerification,
)


@dataclass
class CheckoutDomainPaymentMethodVerification:
apple_pay: CheckoutDomainApplePayVerification

@staticmethod
def from_dict(data: dict[str, Any]) -> CheckoutDomainPaymentMethodVerification:
return CheckoutDomainPaymentMethodVerification(
apple_pay=CheckoutDomainApplePayVerification.from_dict(data["apple_pay"]),
)

@mikeymike mikeymike Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nested in apple pay option so maybe specific for only apple pay but may also possible it could be generic across other future types.

Just noting that with this placement we're leaning on it being generic across future types right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be generic and is aligned with spec

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class CheckoutDomainPaymentMethodVerificationStatus(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
Verified: "CheckoutDomainPaymentMethodVerificationStatus" = "verified"
Unverified: "CheckoutDomainPaymentMethodVerificationStatus" = "unverified"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta


class CheckoutDomainStatus(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
PendingReview: "CheckoutDomainStatus" = "pending_review"
Approved: "CheckoutDomainStatus" = "approved"
Rejected: "CheckoutDomainStatus" = "rejected"
InReview: "CheckoutDomainStatus" = "in_review"
ActionRequired: "CheckoutDomainStatus" = "action_required"
11 changes: 11 additions & 0 deletions paddle_billing/Entities/CheckoutDomains/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from paddle_billing.Entities.CheckoutDomains.CheckoutDomainStatus import CheckoutDomainStatus
from paddle_billing.Entities.CheckoutDomains.CheckoutDomainPaymentMethod import CheckoutDomainPaymentMethod
from paddle_billing.Entities.CheckoutDomains.CheckoutDomainPaymentMethodVerificationStatus import (
CheckoutDomainPaymentMethodVerificationStatus,
)
from paddle_billing.Entities.CheckoutDomains.CheckoutDomainApplePayVerification import (
CheckoutDomainApplePayVerification,
)
from paddle_billing.Entities.CheckoutDomains.CheckoutDomainPaymentMethodVerification import (
CheckoutDomainPaymentMethodVerification,
)
16 changes: 16 additions & 0 deletions paddle_billing/Entities/Collections/CheckoutDomainCollection.py
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.CheckoutDomain import CheckoutDomain


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

return CheckoutDomainCollection(items, paginator)
1 change: 1 addition & 0 deletions paddle_billing/Entities/Collections/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from paddle_billing.Entities.Collections.AddressCollection import AddressCollection
from paddle_billing.Entities.Collections.AdjustmentCollection import AdjustmentCollection
from paddle_billing.Entities.Collections.BusinessCollection import BusinessCollection
from paddle_billing.Entities.Collections.CheckoutDomainCollection import CheckoutDomainCollection
from paddle_billing.Entities.Collections.ClientTokenCollection import ClientTokenCollection
from paddle_billing.Entities.Collections.Collection import Collection
from paddle_billing.Entities.Collections.CreditBalanceCollection import CreditBalanceCollection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from paddle_billing.ResponseParser import ResponseParser

from paddle_billing.Entities.Collections import CheckoutDomainCollection, Paginator
from paddle_billing.Entities.CheckoutDomain import CheckoutDomain

from paddle_billing.Resources.CheckoutDomains.Operations import ListCheckoutDomains, VerifyCheckoutDomainPaymentMethod

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from paddle_billing.Client import Client


class CheckoutDomainsClient:
def __init__(self, client: "Client"):
self.client = client
self.response = None

def list(self, operation: ListCheckoutDomains | None = None) -> CheckoutDomainCollection:
if operation is None:
operation = ListCheckoutDomains()

self.response = self.client.get_raw("/checkout-domains", operation.get_parameters())
parser = ResponseParser(self.response)

return CheckoutDomainCollection.from_list(
parser.get_list(), Paginator(self.client, parser.get_pagination(), CheckoutDomainCollection)
)

def get(self, checkout_domain_id: str) -> CheckoutDomain:
self.response = self.client.get_raw(f"/checkout-domains/{checkout_domain_id}")
parser = ResponseParser(self.response)

return CheckoutDomain.from_dict(parser.get_dict())

def delete(self, checkout_domain_id: str) -> None:
self.client.delete_raw(f"/checkout-domains/{checkout_domain_id}")

return None

def verify_payment_method(
self, checkout_domain_id: str, operation: VerifyCheckoutDomainPaymentMethod
) -> CheckoutDomain:
self.response = self.client.post_raw(f"/checkout-domains/{checkout_domain_id}/verify-payment-method", operation)
parser = ResponseParser(self.response)

return CheckoutDomain.from_dict(parser.get_dict())
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from paddle_billing.EnumStringify import enum_stringify
from paddle_billing.HasParameters import HasParameters

from paddle_billing.Entities.CheckoutDomains import CheckoutDomainStatus

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException

from paddle_billing.Resources.Shared.Operations import Pager


class ListCheckoutDomains(HasParameters):
def __init__(
self,
pager: Pager | None = None,
domain: str | None = None,
statuses: list[CheckoutDomainStatus] | None = None,
):
self.pager = pager
self.domain = domain
self.statuses = statuses if statuses is not None else []

# Validation
for field_name, field_value, field_type in [
("statuses", self.statuses, CheckoutDomainStatus),
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException.array_contains_invalid_types(
field_name, field_type.__name__, invalid_items
)

def get_parameters(self) -> dict[str, str]:
parameters = {}
if self.pager:
parameters.update(self.pager.get_parameters())
if self.domain:
parameters["domain"] = self.domain
if self.statuses:
parameters["status"] = ",".join(map(enum_stringify, self.statuses))

return parameters
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from dataclasses import dataclass

from paddle_billing.Operation import Operation
from paddle_billing.Entities.CheckoutDomains import CheckoutDomainPaymentMethod


@dataclass
class VerifyCheckoutDomainPaymentMethod(Operation):
payment_method: CheckoutDomainPaymentMethod
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from paddle_billing.Resources.CheckoutDomains.Operations.ListCheckoutDomains import ListCheckoutDomains
from paddle_billing.Resources.CheckoutDomains.Operations.VerifyCheckoutDomainPaymentMethod import (
VerifyCheckoutDomainPaymentMethod,
)
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"payment_method": "apple_pay"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"data": {
"id": "chedom_01hv8h6jj90jjz0d71m6hj4r9z",
"domain": "example.com",
"status": "approved",
"payment_method_verification": {
"apple_pay": {
"status": "verified"
}
},
"created_at": "2024-04-12T06:42:58.785000Z",
"updated_at": "2024-04-12T06:42:58.785000Z"
},
"meta": {
"request_id": "cf039cbb-6c2a-485d-b244-501894b797a6"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"data": [
{
"id": "chedom_01hv8h6jj90jjz0d71m6hj4r9z",
"domain": "example.com",
"status": "approved",
"payment_method_verification": {
"apple_pay": {
"status": "verified"
}
},
"created_at": "2024-04-12T06:42:58.785000Z",
"updated_at": "2024-04-12T06:42:58.785000Z"
},
{
"id": "chedom_01hv8h6jj90jjz0d71m6hj4r9y",
"domain": "checkout.example.com",
"status": "pending_review",
"payment_method_verification": {
"apple_pay": {
"status": "unverified"
}
},
"created_at": "2024-04-11T06:42:58.785000Z",
"updated_at": "2024-04-11T06:42:58.785000Z"
}
],
"meta": {
"request_id": "e2923a4b-6230-485f-bd7f-64cc4db2454b",
"pagination": {
"per_page": 50,
"next": "https://api.paddle.com/checkout-domains?after=chedom_01hv8h6jj90jjz0d71m6hj4r9y",
"has_more": false,
"estimated_total": 2
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"data": [
{
"id": "chedom_01hv8h6jj90jjz0d71m6hj4r9z",
"domain": "example.com",
"status": "approved",
"payment_method_verification": {
"apple_pay": {
"status": "verified"
}
},
"created_at": "2024-04-12T06:42:58.785000Z",
"updated_at": "2024-04-12T06:42:58.785000Z"
}
],
"meta": {
"request_id": "cf039cbb-6c2a-485d-b244-501894b797a6",
"pagination": {
"per_page": 1,
"next": "https://sandbox-api.paddle.com/checkout-domains?after=chedom_01hv8h6jj90jjz0d71m6hj4r9z",
"has_more": true,
"estimated_total": 2
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"data": [
{
"id": "chedom_01hv8h6jj90jjz0d71m6hj4r9y",
"domain": "checkout.example.com",
"status": "pending_review",
"payment_method_verification": {
"apple_pay": {
"status": "unverified"
}
},
"created_at": "2024-04-11T06:42:58.785000Z",
"updated_at": "2024-04-11T06:42:58.785000Z"
}
],
"meta": {
"request_id": "cf039cbb-6c2a-485d-b244-501894b797a6",
"pagination": {
"per_page": 1,
"next": "https://sandbox-api.paddle.com/checkout-domains?after=chedom_01hv8h6jj90jjz0d71m6hj4r9y",
"has_more": false,
"estimated_total": 2
}
}
}
Loading
Loading