SubscriptionKore

# API Reference

This section contains the complete API reference.

## Main Interface

SubscriptionKore - Provider-agnostic async subscriptionkore management library.

class subscriptionkore.AppliedDiscount(*, discount_id: str, coupon_code: str | None = None, amount_off: Money | None = None, percent_off: Decimal | None = None, valid_until: datetime | None = None)

  Bases: `BaseModel`

  Discount applied to a subscriptionn.

  amount_off: Money | None
  coupon_code: str | None
  discount_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_off': FieldInfo(annotation=Union[Money, NoneType], required=False, default=None), 'coupon_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'discount_id': FieldInfo(annotation=str, required=True), 'percent_off': FieldInfo(annotation=Union[Decimal, NoneType], required=False, default=None), 'valid_until': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  percent_off: Decimal | None
  valid_until: datetime | None

class subscriptionkore.BillingPeriod(*, interval: Interval, interval_count: Annotated[int, Ge(ge=1)] = 1, anchor_date: datetime | None = None)

  Bases: `BaseModel`

  Billing period configuration.

  anchor_date: datetime | None
  property display_name: str
  interval: Interval
  interval_count: int
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'anchor_date': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'interval': FieldInfo(annotation=Interval, required=True), 'interval_count': FieldInfo(annotation=int, required=False, default=1, metadata=[Ge(ge=1)])}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  classmethod monthly() → BillingPeriod
  classmethod weekly() → BillingPeriod
  classmethod yearly() → BillingPeriod

exception subscriptionkore.ConfigurationError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for configuration errors.

class subscriptionkore.Customer(*, id: str = None, external_id: str, email: EmailStr, name: str | None = None, provider_refs: list[ProviderReference] = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Customer domain entity.

  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  billing_address: Address | None
  created_at: datetime
  email: EmailStr
  external_id: str
  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'billing_address': FieldInfo(annotation=Union[Address, NoneType], required=False, default=None), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'email': FieldInfo(annotation=EmailStr, required=True), 'external_id': FieldInfo(annotation=str, required=True), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'tax_info': FieldInfo(annotation=Union[TaxInfo, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str | None
  provider_refs: list[ProviderReference]
  tax_info: TaxInfo | None
  update(email: str | None = None, name: str | None = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict[str, Any] | None = None) → None

    Update customer fields.

  updated_at: datetime

class subscriptionkore.CustomerCreated(*, event_id: str = None, event_type: str = 'CustomerCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, customer: Customer)

  Bases: `DomainEvent`

  Emitted when a customer is created.

  customer: Customer
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer': FieldInfo(annotation=Customer, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='CustomerCreated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

class subscriptionkore.CustomerEntitlement(*, customer_id: str, entitlement_key: str, current_value: bool | int | str, value_type: EntitlementValueType, source: EntitlementSource, expires_at: datetime | None = None, subscription_id: str | None = None, plan_id: str | None = None)

  Bases: `BaseModel`

  Resolved entitlement for a customer.

  as_bool() → bool

    Get value as boolean.

  as_int() → int | None

    Get value as integer (None for unlimited).

  current_value: bool | int | str
  customer_id: str
  entitlement_key: str
  expires_at: datetime | None
  is_boolean() → bool
  is_expired() → bool

    Check if entitlement has expired.

  is_numeric() → bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'current_value': FieldInfo(annotation=Union[bool, int, str], required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'expires_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'plan_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'source': FieldInfo(annotation=EntitlementSource, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  plan_id: str | None
  source: EntitlementSource
  subscription_id: str | None
  value_type: EntitlementValueType

class subscriptionkore.CustomerUpdated(*, event_id: str = None, event_type: str = 'CustomerUpdated', occurred_at: datetime = None, metadata: dict[str, Any] = None, customer: Customer, changed_fields: list[str])

  Bases: `DomainEvent`

  Emitted when a customer is updated.

  changed_fields: list[str]
  customer: Customer
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'changed_fields': FieldInfo(annotation=list[str], required=True), 'customer': FieldInfo(annotation=Customer, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='CustomerUpdated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

exception subscriptionkore.DomainError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for domain errors.

class subscriptionkore.DomainEvent(*, event_id: str = None, event_type: str = '', occurred_at: datetime = None, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Base class for all domain events.

  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPlanChanged'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime

exception subscriptionkore.DuplicateEntityError(entity_type: str, identifier: str)

  Bases: `DomainError`

  Raised when attempting to create a duplicate entity.

class subscriptionkore.Entitlement(*, id: str = None, key: str, name: str, description: str | None = None, value_type: EntitlementValueType, default_value: bool | int | str | None = None, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Entitlement definition entity.

  created_at: datetime
  default_value: bool | int | str | None
  description: str | None
  id: str
  key: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'default_value': FieldInfo(annotation=Union[bool, int, str, NoneType], required=False, default=None), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'key': FieldInfo(annotation=str, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  updated_at: datetime
  value_type: EntitlementValueType

exception subscriptionkore.EntitlementError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for entitlement errors.

exception subscriptionkore.EntitlementNotFoundError(key: str)

  Bases: `EntitlementError`

  Raised when an entitlement is not found.

class subscriptionkore.EntitlementOverride(*, id: str = None, customer_id: str, entitlement_key: str, value: bool | int | str, value_type: EntitlementValueType, reason: str | None = None, expires_at: datetime | None = None, created_by: str | None = None, created_at: datetime = None)

  Bases: `BaseModel`

  Manual entitlement override for a customer.

  created_at: datetime
  created_by: str | None
  customer_id: str
  entitlement_key: str
  expires_at: datetime | None
  id: str
  is_expired() → bool

    Check if override has expired.

  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'created_by': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'customer_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'expires_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'value': FieldInfo(annotation=Union[bool, int, str], required=True), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  reason: str | None
  value: bool | int | str
  value_type: EntitlementValueType

class subscriptionkore.EntitlementValueType(*values)

  Bases: `StrEnum`

  Types of entitlement values.

  BOOLEAN = 'boolean'
  NUMERIC = 'numeric'
  STRING = 'string'
  UNLIMITED = 'unlimited'

exception subscriptionkore.EntityNotFoundError(entity_type: str, entity_id: str)

  Bases: `DomainError`

  Raised when an entity is not found.

class subscriptionkore.Interval(*values)

  Bases: `StrEnum`

  Billing interval types.

  DAY = 'day'
  MONTH = 'month'
  WEEK = 'week'
  YEAR = 'year'

exception subscriptionkore.InvalidConfigurationError(message: str, details: dict[str, Any] | None = None)

  Bases: `ConfigurationError`

  Raised when configuration is invalid.

exception subscriptionkore.InvalidStateTransitionError(from_state: SubscriptionStatus, to_state: SubscriptionStatus, reason: str | None = None)

  Bases: `DomainError`

  Raised when an invalid state transition is attempted.

class subscriptionkore.Invoice(*, id: str = None, customer_id: str, subscriptionkore_id: str | None = None, provider_ref: ProviderReference, status: InvoiceStatus = InvoiceStatus.DRAFT, subtotal: Money, tax: Money = None, discount_amount: Money = None, total: Money, amount_paid: Money = None, amount_due: Money, currency: Currency = Currency.USD, line_items: list[InvoiceLineItem] = None, period: DateRange | None = None, due_date: datetime | None = None, paid_at: datetime | None = None, invoice_pdf_url: str | None = None, hosted_invoice_url: str | None = None, metadata: dict[str, Any] = None, created_at: datetime = None)

  Bases: `BaseModel`

  Invoice domain entity.

  amount_due: Money
  amount_paid: Money
  created_at: datetime
  currency: Currency
  customer_id: str
  discount_amount: Money
  due_date: datetime | None
  hosted_invoice_url: str | None
  id: str
  invoice_pdf_url: str | None
  is_open() → bool

    Check if invoice is open for payment.

  is_overdue() → bool

    Check if invoice is past due date.

  is_paid() → bool

    Check if invoice is fully paid.

  line_items: list[InvoiceLineItem]
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_due': FieldInfo(annotation=Money, required=True), 'amount_paid': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'currency': FieldInfo(annotation=Currency, required=False, default=<Currency.USD: 'USD'>), 'customer_id': FieldInfo(annotation=str, required=True), 'discount_amount': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'due_date': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'hosted_invoice_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'invoice_pdf_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'line_items': FieldInfo(annotation=list[InvoiceLineItem], required=False, default_factory=list), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'paid_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'period': FieldInfo(annotation=Union[DateRange, NoneType], required=False, default=None), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'status': FieldInfo(annotation=InvoiceStatus, required=False, default=<InvoiceStatus.DRAFT: 'draft'>), 'subscriptionkore_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'subtotal': FieldInfo(annotation=Money, required=True), 'tax': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'total': FieldInfo(annotation=Money, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  paid_at: datetime | None
  period: DateRange | None
  provider_ref: ProviderReference
  remaining_balance() → Money

    Get remaining balance to be paid.

  status: InvoiceStatus
  subscriptionkore_id: str | None
  subtotal: Money
  tax: Money
  total: Money

class subscriptionkore.InvoiceCreated(*, event_id: str = None, event_type: str = 'InvoiceCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, invoice: Invoice, customer_id: str, subscription_id: str | None = None)

  Bases: `DomainEvent`

  Emitted when an invoice is created.

  customer_id: str
  invoice: Invoice
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='InvoiceCreated'), 'invoice': FieldInfo(annotation=Invoice, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscription_id: str | None

class subscriptionkore.InvoiceLineItem(*, id: str = None, description: str, quantity: int = 1, unit_amount: Money, amount: Money, period: DateRange | None = None, proration: bool = False, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Line item on an invoice.

  amount: Money
  description: str
  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'description': FieldInfo(annotation=str, required=True), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'period': FieldInfo(annotation=Union[DateRange, NoneType], required=False, default=None), 'proration': FieldInfo(annotation=bool, required=False, default=False), 'quantity': FieldInfo(annotation=int, required=False, default=1), 'unit_amount': FieldInfo(annotation=Money, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  period: DateRange | None
  proration: bool
  quantity: int
  unit_amount: Money

class subscriptionkore.InvoicePaid(*, event_id: str = None, event_type: str = 'InvoicePaid', occurred_at: datetime = None, metadata: dict[str, Any] = None, invoice: Invoice, customer_id: str, subscription_id: str | None = None, amount_paid: Money)

  Bases: `DomainEvent`

  Emitted when an invoice is paid.

  amount_paid: Money
  customer_id: str
  invoice: Invoice
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_paid': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='InvoicePaid'), 'invoice': FieldInfo(annotation=Invoice, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscription_id: str | None

class subscriptionkore.InvoiceStatus(*values)

  Bases: `StrEnum`

  Invoice status values.

  DRAFT = 'draft'
  OPEN = 'open'
  PAID = 'paid'
  UNCOLLECTIBLE = 'uncollectible'
  VOID = 'void'

exception subscriptionkore.MissingProviderCredentialsError(provider: str, missing_fields: list[str])

  Bases: `ConfigurationError`

  Raised when provider credentials are missing.

class subscriptionkore.Money(*, amount: Decimal, currency: Currency = Currency.USD)

  Bases: `BaseModel`

  Immutable monetary value with currency.

  amount: Decimal
  currency: Currency
  classmethod from_cents(cents: int, currency: Currency = Currency.USD) → Money

    Create Money from minor units (cents).

  is_negative() → bool
  is_positive() → bool
  is_zero() → bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Decimal, required=True, description='Amount in major currency units'), 'currency': FieldInfo(annotation=Currency, required=False, default=<Currency.USD: 'USD'>)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  classmethod normalize_amount(v: Any) → Decimal
  to_cents() → int

    Convert to minor units (cents).

  classmethod zero(currency: Currency = Currency.USD) → Money

class subscriptionkore.PauseConfig(*, resumes_at: datetime | None = None, behavior: PauseBehavior = PauseBehavior.VOID)

  Bases: `BaseModel`

  Subscription pause configuration.

  behavior: PauseBehavior
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'behavior': FieldInfo(annotation=PauseBehavior, required=False, default=<PauseBehavior.VOID: 'void'>), 'resumes_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  resumes_at: datetime | None

class subscriptionkore.PaymentEvent(*, id: str = None, provider_ref: ProviderReference, customer_id: str, subscriptionkore_id: str | None = None, invoice_id: str | None = None, event_type: PaymentEventType, amount: Money, status: PaymentStatus, failure_reason: str | None = None, failure_code: str | None = None, payment_method_type: str | None = None, payment_method_last4: str | None = None, occurred_at: datetime = None, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Payment event domain entity.

  amount: Money
  customer_id: str
  event_type: PaymentEventType
  failure_code: str | None
  failure_reason: str | None
  id: str
  invoice_id: str | None
  is_failed() → bool

    Check if payment failed.

  is_successful() → bool

    Check if payment succeeded.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_type': FieldInfo(annotation=PaymentEventType, required=True), 'failure_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'failure_reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_method_last4': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'payment_method_type': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'status': FieldInfo(annotation=PaymentStatus, required=True), 'subscriptionkore_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  payment_method_last4: str | None
  payment_method_type: str | None
  provider_ref: ProviderReference
  status: PaymentStatus
  subscriptionkore_id: str | None

class subscriptionkore.PaymentEventType(*values)

  Bases: `StrEnum`

  Payment event types.

  PAYMENT_DISPUTED = 'payment_disputed'
  PAYMENT_FAILED = 'payment_failed'
  PAYMENT_REFUNDED = 'payment_refunded'
  PAYMENT_SUCCEEDED = 'payment_succeeded'

class subscriptionkore.PaymentFailed(*, event_id: str = None, event_type: str = 'PaymentFailed', occurred_at: datetime = None, metadata: dict[str, Any] = None, payment_event: PaymentEvent, customer_id: str, subscription_id: str | None = None, invoice_id: str | None = None, amount: Money, failure_reason: str | None = None, failure_code: str | None = None, attempt_count: int = 1)

  Bases: `DomainEvent`

  Emitted when a payment fails.

  amount: Money
  attempt_count: int
  customer_id: str
  failure_code: str | None
  failure_reason: str | None
  invoice_id: str | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'attempt_count': FieldInfo(annotation=int, required=False, default=1), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='PaymentFailed'), 'failure_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'failure_reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_event': FieldInfo(annotation=PaymentEvent, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  payment_event: PaymentEvent
  subscription_id: str | None

class subscriptionkore.PaymentStatus(*values)

  Bases: `StrEnum`

  Payment status values.

  DISPUTED = 'disputed'
  FAILED = 'failed'
  PARTIALLY_REFUNDED = 'partially_refunded'
  PENDING = 'pending'
  REFUNDED = 'refunded'
  SUCCEEDED = 'succeeded'

class subscriptionkore.PaymentSucceeded(*, event_id: str = None, event_type: str = 'PaymentSucceeded', occurred_at: datetime = None, metadata: dict[str, Any] = None, payment_event: PaymentEvent, customer_id: str, subscription_id: str | None = None, invoice_id: str | None = None, amount: Money)

  Bases: `DomainEvent`

  Emitted when a payment succeeds.

  amount: Money
  customer_id: str
  invoice_id: str | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='PaymentSucceeded'), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_event': FieldInfo(annotation=PaymentEvent, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  payment_event: PaymentEvent
  subscription_id: str | None

class subscriptionkore.Plan(*, id: str = None, product_id: str, name: str, description: str | None = None, provider_refs: list[ProviderReference] = None, price: Money, billing_period: BillingPeriod, trial_period_days: int | None = None, entitlements: list[PlanEntitlement] = None, active: bool = True, tier: int = 0, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Plan domain entity (a pricing tier for a product).

  active: bool
  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  billing_period: BillingPeriod
  created_at: datetime
  deactivate() → None

    Deactivate the plan.

  description: str | None
  entitlements: list[PlanEntitlement]
  get_entitlement_value(key: str) → bool | int | str | None

    Get entitlement value by key.

  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  is_downgrade_from(other: Plan) → bool

    Check if this plan is a downgrade from another.

  is_upgrade_from(other: Plan) → bool

    Check if this plan is an upgrade from another.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'active': FieldInfo(annotation=bool, required=False, default=True), 'billing_period': FieldInfo(annotation=BillingPeriod, required=True), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'entitlements': FieldInfo(annotation=list[PlanEntitlement], required=False, default_factory=list), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'price': FieldInfo(annotation=Money, required=True), 'product_id': FieldInfo(annotation=str, required=True), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'tier': FieldInfo(annotation=int, required=False, default=0, description='For upgrade/downgrade ordering'), 'trial_period_days': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  price: Money
  product_id: str
  provider_refs: list[ProviderReference]
  tier: int
  trial_period_days: int | None
  updated_at: datetime

class subscriptionkore.PlanEntitlement(*, entitlement_id: str, entitlement_key: str, value: bool | int | str | None, value_type: EntitlementValueType)

  Bases: `BaseModel`

  Entitlement configuration for a plan.

  entitlement_id: str
  entitlement_key: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'entitlement_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'value': FieldInfo(annotation=Union[bool, int, str, NoneType], required=True), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  value: bool | int | str | None
  value_type: EntitlementValueType

class subscriptionkore.Product(*, id: str = None, name: str, description: str | None = None, provider_refs: list[ProviderReference] = None, active: bool = True, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Product domain entity.

  activate() → None

    Activate the product.

  active: bool
  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  created_at: datetime
  deactivate() → None

    Deactivate the product.

  description: str | None
  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'active': FieldInfo(annotation=bool, required=False, default=True), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  provider_refs: list[ProviderReference]
  updated_at: datetime

exception subscriptionkore.ProviderAPIError(message: str, provider: str, status_code: int, provider_message: str | None = None, provider_code: str | None = None)

  Bases: `ProviderError`

  Raised for non-recoverable API errors from providers.

exception subscriptionkore.ProviderAuthenticationError(provider: str, message: str | None = None)

  Bases: `ProviderError`

  Raised when authentication fails. Non-recoverable.

exception subscriptionkore.ProviderError(message: str, provider: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for provider errors.

exception subscriptionkore.ProviderNetworkError(provider: str, original_error: Exception)

  Bases: `ProviderError`

  Raised for network errors. Recoverable with retry.

exception subscriptionkore.ProviderRateLimitError(provider: str, retry_after: int | None = None)

  Bases: `ProviderError`

  Raised when provider rate limit is exceeded. Recoverable with retry.

class subscriptionkore.ProviderReference(*, provider: ProviderType, external_id: str, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Reference to an entity in a payment provider.

  external_id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'external_id': FieldInfo(annotation=str, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'provider': FieldInfo(annotation=ProviderType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  provider: ProviderType

class subscriptionkore.ProviderType(*values)

  Bases: `StrEnum`

  Supported payment providers.

  CHARGEBEE = 'chargebee'
  LEMONSQUEEZY = 'lemonsqueezy'
  PADDLE = 'paddle'
  STRIPE = 'stripe'

exception subscriptionkore.RepositoryError(operation: str, entity_type: str, original_error: Exception)

  Bases: `SubscriptionKoreError`

  Raised when a repository operation fails.

class subscriptionkore.Subscription(*, id: str = None, customer_id: str, plan_id: str, provider_ref: ProviderReference, status: SubscriptionStatus = SubscriptionStatus.INCOMPLETE, current_period: DateRange, trial_end: datetime | None = None, cancel_at_period_end: bool = False, canceled_at: datetime | None = None, ended_at: datetime | None = None, pause_collection: PauseConfig | None = None, discount: AppliedDiscount | None = None, quantity: int = 1, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Subscription domain entity.

  apply_discount(discount: AppliedDiscount) → None

    Apply a discount to the subscriptionn.

  cancel_at_period_end: bool
  canceled_at: datetime | None
  created_at: datetime
  current_period: DateRange
  customer_id: str
  days_until_trial_ends() → int | None

    Get days until trial ends, or None if not trialing.

  discount: AppliedDiscount | None
  ended_at: datetime | None
  has_ended() → bool

    Check if subscriptionn has permanently ended.

  id: str
  is_active() → bool

    Check if subscriptionn is in an active state.

  is_canceled() → bool

    Check if subscriptionn is canceled.

  is_past_due() → bool

    Check if subscriptionn has payment issues.

  is_paused() → bool

    Check if subscriptionn is paused.

  is_trialing() → bool

    Check if subscriptionn is in trial.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'cancel_at_period_end': FieldInfo(annotation=bool, required=False, default=False), 'canceled_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'current_period': FieldInfo(annotation=DateRange, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'discount': FieldInfo(annotation=Union[AppliedDiscount, NoneType], required=False, default=None), 'ended_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'pause_collection': FieldInfo(annotation=Union[PauseConfig, NoneType], required=False, default=None), 'plan_id': FieldInfo(annotation=str, required=True), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'quantity': FieldInfo(annotation=int, required=False, default=1), 'status': FieldInfo(annotation=SubscriptionStatus, required=False, default=<SubscriptionStatus.INCOMPLETE: 'incomplete'>), 'trial_end': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  pause_collection: PauseConfig | None
  plan_id: str
  provider_ref: ProviderReference
  quantity: int
  remove_discount() → None

    Remove discount from subscriptionn.

  schedule_cancellation() → None

    Schedule cancellation at period end.

  status: SubscriptionStatus
  trial_end: datetime | None
  unschedule_cancellation() → None

    Remove scheduled cancellation.

  updated_at: datetime
  will_cancel_at_period_end() → bool

    Check if subscriptionn is scheduled to cancel.

class subscriptionkore.SubscriptionActivated(*, event_id: str = None, event_type: str = 'SubscriptionActivated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore becomes active.

  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionActivated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.SubscriptionCanceled(*, event_id: str = None, event_type: str = 'SubscriptionCanceled', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str, immediate: bool, reason: str | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is canceled.

  customer_id: str
  immediate: bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionCanceled'), 'immediate': FieldInfo(annotation=bool, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  plan_id: str
  reason: str | None
  subscriptionkore: Subscription

class subscriptionkore.SubscriptionCreated(*, event_id: str = None, event_type: str = 'SubscriptionCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is created.

  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionCreated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.SubscriptionKore(config: SubscriptionKoreConfig)

  Bases: `object`

  Main entry point for the SubscriptionKore library.

  Provides access to all subscription management functionality.

  Example:

      from subscriptionkore import SubscriptionKore, SubscriptionKoreConfig
      from subscriptionkore.config import StripeConfig

      config = SubscriptionKoreConfig(
          database_url="postgresql+asyncpg://user:pass@localhost/db",
          stripe=StripeConfig(
              api_key="sk_test_...",
              webhook_secret="whsec_...",
          ),
      )

      async with SubscriptionKore(config) as subscriptionkore:
          # Create a customer
          customer = await subscriptionkore.customers.create(
              external_id="user_123",
              email="user@example.com",
          )

          # Create a subscription
          subscription = await subscriptionkore.subscriptions.create(
              customer_id=customer.id,
              plan_id="plan_abc",
          )

          # Check entitlements
          has_access = await subscriptionkore.entitlements.has_access(
              customer_id=customer.id,
              entitlement_key="premium_features",
          )

  async check_entitlement(customer_id: str, entitlement_key: str) → CustomerEntitlement

    Convenience method to check an entitlement.

  async close() → None

    Close all connections and clean up resources.

  property configured_providers: list[ProviderType]

    Get list of configured providers.

  async create_customer(external_id: str, email: str, name: str | None = None, provider_type: ProviderType | None = None) → Customer

    Convenience method to create a customer.

  async create_subscription(customer_id: str, plan_id: str, quantity: int = 1, trial_period_days: int | None = None, provider_type: ProviderType | None = None) → Subscription

    Convenience method to create a subscription.

  property event_bus: EventBusPort

    Access the event bus for subscribing to domain events.

  async get_customer_manager(provider_type: ProviderType | None = None) → CustomerManager

    Get a customer manager instance.

  async get_entitlement_service() → EntitlementService

    Get an entitlement service instance.

  get_provider(provider_type: ProviderType) → PaymentProviderPort

    Get a specific provider adapter.

  async get_subscription_manager(provider_type: ProviderType | None = None) → SubscriptionManager

    Get a subscription manager instance.

  async get_webhook_processor() → WebhookProcessor

    Get a webhook processor instance.

  async has_access(customer_id: str, entitlement_key: str) → bool

    Convenience method to check feature access.

  async initialize() → None

    Initialize all components.

  on_event(event_type: type['DomainEvent']) → Callable[[Callable[['DomainEvent'], Awaitable[None]]], Callable[['DomainEvent'], Awaitable[None]]]

    Decorator to subscribe to domain events.

    Example:

        @subscriptionkore.on_event(SubscriptionActivated)
        async def handle_activation(event: SubscriptionActivated):
            await send_welcome_email(event.customer_id)

class subscriptionkore.SubscriptionKoreConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, database_url: str, redis_url: str | None = None, stripe: StripeConfig | None = None, paddle: PaddleConfig | None = None, lemonsqueezy: LemonSqueezyConfig | None = None, chargebee: ChargebeeConfig | None = None, default_provider: ProviderType = ProviderType.STRIPE, webhook_processing: Literal['sync', 'async'] = 'sync', entitlement_cache_ttl: int = 300, processed_event_ttl_days: int = 7)

  Bases: `BaseSettings`

  Main configuration for SubscriptionKore.

  chargebee: ChargebeeConfig | None
  database_url: str
  default_provider: ProviderType
  entitlement_cache_ttl: int
  get_configured_providers() → list[ProviderType]

    Get list of configured providers.

  get_provider_config(provider: ProviderType) → StripeConfig | PaddleConfig | LemonSqueezyConfig | ChargebeeConfig | None

    Get configuration for a specific provider.

  lemonsqueezy: LemonSqueezyConfig | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': '__', 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'SUBSCRIPTIONKORE_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'chargebee': FieldInfo(annotation=Union[ChargebeeConfig, NoneType], required=False, default=None), 'database_url': FieldInfo(annotation=str, required=True, description='PostgreSQL async connection URL'), 'default_provider': FieldInfo(annotation=ProviderType, required=False, default=<ProviderType.STRIPE: 'stripe'>, description='Default payment provider to use'), 'entitlement_cache_ttl': FieldInfo(annotation=int, required=False, default=300, description='Entitlement cache TTL in seconds'), 'lemonsqueezy': FieldInfo(annotation=Union[LemonSqueezyConfig, NoneType], required=False, default=None), 'paddle': FieldInfo(annotation=Union[PaddleConfig, NoneType], required=False, default=None), 'processed_event_ttl_days': FieldInfo(annotation=int, required=False, default=7, description='Days to keep processed event records'), 'redis_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Redis connection URL'), 'stripe': FieldInfo(annotation=Union[StripeConfig, NoneType], required=False, default=None), 'webhook_processing': FieldInfo(annotation=Literal['sync', 'async'], required=False, default='sync', description='Webhook processing mode')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  paddle: PaddleConfig | None
  processed_event_ttl_days: int
  redis_url: str | None
  stripe: StripeConfig | None
  classmethod validate_database_url(v: str) → str

    Validate database URL is async-compatible.

  validate_default_provider_configured() → SubscriptionKoreConfig

    Ensure default provider has configuration.

  webhook_processing: Literal['sync', 'async']

exception subscriptionkore.SubscriptionKoreError(message: str, details: dict[str, Any] | None = None)

  Bases: `Exception`

  Base exception for all subscriptionkore errors.

class subscriptionkore.SubscriptionPastDue(*, event_id: str = None, event_type: str = 'SubscriptionPastDue', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, invoice_id: str | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore becomes past due.

  customer_id: str
  invoice_id: str | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPastDue'), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscriptionkore: Subscription

class subscriptionkore.SubscriptionPaused(*, event_id: str = None, event_type: str = 'SubscriptionPaused', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, resumes_at: datetime | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is paused.

  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPaused'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'resumes_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  resumes_at: datetime | None
  subscriptionkore: Subscription

class subscriptionkore.SubscriptionPlanChanged(*, event_id: str = None, event_type: str = 'SubscriptionPlanChanged', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, previous_plan_id: str, new_plan_id: str, is_upgrade: bool)

  Bases: `DomainEvent`

  Emitted when subscriptionkore plan is changed.

  customer_id: str
  is_upgrade: bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPlanChanged'), 'is_upgrade': FieldInfo(annotation=bool, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'new_plan_id': FieldInfo(annotation=str, required=True), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'previous_plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  new_plan_id: str
  previous_plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.SubscriptionResumed(*, event_id: str = None, event_type: str = 'SubscriptionResumed', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is resumed.

  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionResumed'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscriptionkore: Subscription

class subscriptionkore.SubscriptionStatus(*values)

  Bases: `StrEnum`

  Subscription status values.

  ACTIVE = 'active'
  CANCELED = 'canceled'
  EXPIRED = 'expired'
  INCOMPLETE = 'incomplete'
  INCOMPLETE_EXPIRED = 'incomplete_expired'
  PAST_DUE = 'past_due'
  PAUSED = 'paused'
  TRIALING = 'trialing'
  UNPAID = 'unpaid'

class subscriptionkore.SubscriptionTrialEnded(*, event_id: str = None, event_type: str = 'SubscriptionTrialEnded', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, converted: bool)

  Bases: `DomainEvent`

  Emitted when a trial ends.

  converted: bool
  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'converted': FieldInfo(annotation=bool, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionTrialEnded'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscriptionkore: Subscription

class subscriptionkore.SubscriptionTrialStarted(*, event_id: str = None, event_type: str = 'SubscriptionTrialStarted', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, trial_end: datetime)

  Bases: `DomainEvent`

  Emitted when a trial starts.

  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionTrialStarted'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True), 'trial_end': FieldInfo(annotation=datetime, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscriptionkore: Subscription
  trial_end: datetime

class subscriptionkore.SubscriptionUpdated(*, event_id: str = None, event_type: str = 'SubscriptionUpdated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, changed_fields: list[str])

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is updated.

  changed_fields: list[str]
  customer_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'changed_fields': FieldInfo(annotation=list[str], required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionUpdated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  subscriptionkore: Subscription

exception subscriptionkore.UsageLimitExceededError(entitlement_key: str, limit: int, current_usage: int, requested: int)

  Bases: `EntitlementError`

  Raised when a usage limit is exceeded.

exception subscriptionkore.ValidationError(field: str, message: str)

  Bases: `DomainError`

  Raised when validation fails.

exception subscriptionkore.WebhookError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for webhook errors.

exception subscriptionkore.WebhookPayloadInvalidError(provider: str, reason: str)

  Bases: `WebhookError`

  Raised when webhook payload cannot be parsed.

exception subscriptionkore.WebhookProcessingError(event_id: str, reason: str)

  Bases: `WebhookError`

  Raised when webhook processing fails.

exception subscriptionkore.WebhookSignatureInvalidError(provider: str)

  Bases: `WebhookError`

  Raised when webhook signature verification fails.

## Configuration

Configuration management.

class subscriptionkore.config.ChargebeeConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, site: str, api_key: str, webhook_username: str | None = None, webhook_password: str | None = None)

  Bases: `BaseSettings`

  Chargebee provider configuration.

  api_key: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'CHARGEBEE_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'api_key': FieldInfo(annotation=str, required=True, description='Chargebee API key'), 'site': FieldInfo(annotation=str, required=True, description='Chargebee site name'), 'webhook_password': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Webhook basic auth password'), 'webhook_username': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Webhook basic auth username')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  site: str
  webhook_password: str | None
  webhook_username: str | None

class subscriptionkore.config.LemonSqueezyConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, api_key: str, webhook_secret: str, store_id: str)

  Bases: `BaseSettings`

  LemonSqueezy provider configuration.

  api_key: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'LEMONSQUEEZY_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'api_key': FieldInfo(annotation=str, required=True, description='LemonSqueezy API key'), 'store_id': FieldInfo(annotation=str, required=True, description='LemonSqueezy store ID'), 'webhook_secret': FieldInfo(annotation=str, required=True, description='LemonSqueezy webhook signing secret')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  store_id: str
  webhook_secret: str

class subscriptionkore.config.PaddleConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, api_key: str, webhook_secret: str, environment: Literal['sandbox', 'production'] = 'sandbox', seller_id: str | None = None)

  Bases: `BaseSettings`

  Paddle provider configuration.

  api_key: str
  environment: Literal['sandbox', 'production']
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'PADDLE_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'api_key': FieldInfo(annotation=str, required=True, description='Paddle API key'), 'environment': FieldInfo(annotation=Literal['sandbox', 'production'], required=False, default='sandbox'), 'seller_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Paddle seller/vendor ID'), 'webhook_secret': FieldInfo(annotation=str, required=True, description='Paddle webhook secret key')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  seller_id: str | None
  webhook_secret: str

class subscriptionkore.config.StripeConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, api_key: str, webhook_secret: str, api_version: str = '2024-06-20')

  Bases: `BaseSettings`

  Stripe provider configuration.

  api_key: str
  api_version: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'STRIPE_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'api_key': FieldInfo(annotation=str, required=True, description='Stripe secret API key'), 'api_version': FieldInfo(annotation=str, required=False, default='2024-06-20', description='Stripe API version'), 'webhook_secret': FieldInfo(annotation=str, required=True, description='Stripe webhook signing secret')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  webhook_secret: str

class subscriptionkore.config.SubscriptionKoreConfig(_case_sensitive: bool | None = None, _nested_model_default_partial_update: bool | None = None, _env_prefix: str | None = None, _env_file: DotenvType | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_ignore_empty: bool | None = None, _env_nested_delimiter: str | None = None, _env_parse_none_str: str | None = None, _env_parse_enums: bool | None = None, _cli_prog_name: str | None = None, _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, _cli_settings_source: CliSettingsSource[Any] | None = None, _cli_parse_none_str: str | None = None, _cli_hide_none_type: bool | None = None, _cli_avoid_json: bool | None = None, _cli_enforce_required: bool | None = None, _cli_use_class_docs_for_groups: bool | None = None, _cli_exit_on_error: bool | None = None, _cli_prefix: str | None = None, _cli_flag_prefix_char: str | None = None, _cli_implicit_flags: bool | None = None, _cli_ignore_unknown_args: bool | None = None, _secrets_dir: PathType | None = None, *, database_url: str, redis_url: str | None = None, stripe: StripeConfig | None = None, paddle: PaddleConfig | None = None, lemonsqueezy: LemonSqueezyConfig | None = None, chargebee: ChargebeeConfig | None = None, default_provider: ProviderType = ProviderType.STRIPE, webhook_processing: Literal['sync', 'async'] = 'sync', entitlement_cache_ttl: int = 300, processed_event_ttl_days: int = 7)

  Bases: `BaseSettings`

  Main configuration for SubscriptionKore.

  chargebee: ChargebeeConfig | None
  database_url: str
  default_provider: ProviderType
  entitlement_cache_ttl: int
  get_configured_providers() → list[ProviderType]

    Get list of configured providers.

  get_provider_config(provider: ProviderType) → StripeConfig | PaddleConfig | LemonSqueezyConfig | ChargebeeConfig | None

    Get configuration for a specific provider.

  lemonsqueezy: LemonSqueezyConfig | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_use_class_docs_for_groups': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': '__', 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'SUBSCRIPTIONKORE_', 'extra': 'forbid', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_', 'settings_'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_file': None, 'yaml_file_encoding': None}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'chargebee': FieldInfo(annotation=Union[ChargebeeConfig, NoneType], required=False, default=None), 'database_url': FieldInfo(annotation=str, required=True, description='PostgreSQL async connection URL'), 'default_provider': FieldInfo(annotation=ProviderType, required=False, default=<ProviderType.STRIPE: 'stripe'>, description='Default payment provider to use'), 'entitlement_cache_ttl': FieldInfo(annotation=int, required=False, default=300, description='Entitlement cache TTL in seconds'), 'lemonsqueezy': FieldInfo(annotation=Union[LemonSqueezyConfig, NoneType], required=False, default=None), 'paddle': FieldInfo(annotation=Union[PaddleConfig, NoneType], required=False, default=None), 'processed_event_ttl_days': FieldInfo(annotation=int, required=False, default=7, description='Days to keep processed event records'), 'redis_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, description='Redis connection URL'), 'stripe': FieldInfo(annotation=Union[StripeConfig, NoneType], required=False, default=None), 'webhook_processing': FieldInfo(annotation=Literal['sync', 'async'], required=False, default='sync', description='Webhook processing mode')}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  paddle: PaddleConfig | None
  processed_event_ttl_days: int
  redis_url: str | None
  stripe: StripeConfig | None
  classmethod validate_database_url(v: str) → str

    Validate database URL is async-compatible.

  validate_default_provider_configured() → SubscriptionKoreConfig

    Ensure default provider has configuration.

  webhook_processing: Literal['sync', 'async']

## Core Models

Subscription domain model.

class subscriptionkore.core.models.subscription.AppliedDiscount(*, discount_id: str, coupon_code: str | None = None, amount_off: Money | None = None, percent_off: Decimal | None = None, valid_until: datetime | None = None)

  Bases: `BaseModel`

  Discount applied to a subscriptionn.

  amount_off: Money | None
  coupon_code: str | None
  discount_id: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_off': FieldInfo(annotation=Union[Money, NoneType], required=False, default=None), 'coupon_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'discount_id': FieldInfo(annotation=str, required=True), 'percent_off': FieldInfo(annotation=Union[Decimal, NoneType], required=False, default=None), 'valid_until': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  percent_off: Decimal | None
  valid_until: datetime | None

class subscriptionkore.core.models.subscription.PauseBehavior(*values)

  Bases: `StrEnum`

  Pause behavior options.

  KEEP_AS_DRAFT = 'keep_as_draft'
  MARK_UNCOLLECTIBLE = 'mark_uncollectible'
  VOID = 'void'

class subscriptionkore.core.models.subscription.PauseConfig(*, resumes_at: datetime | None = None, behavior: PauseBehavior = PauseBehavior.VOID)

  Bases: `BaseModel`

  Subscription pause configuration.

  behavior: PauseBehavior
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'behavior': FieldInfo(annotation=PauseBehavior, required=False, default=<PauseBehavior.VOID: 'void'>), 'resumes_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  resumes_at: datetime | None

class subscriptionkore.core.models.subscription.Subscription(*, id: str = None, customer_id: str, plan_id: str, provider_ref: ProviderReference, status: SubscriptionStatus = SubscriptionStatus.INCOMPLETE, current_period: DateRange, trial_end: datetime | None = None, cancel_at_period_end: bool = False, canceled_at: datetime | None = None, ended_at: datetime | None = None, pause_collection: PauseConfig | None = None, discount: AppliedDiscount | None = None, quantity: int = 1, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Subscription domain entity.

  apply_discount(discount: AppliedDiscount) → None

    Apply a discount to the subscriptionn.

  cancel_at_period_end: bool
  canceled_at: datetime | None
  created_at: datetime
  current_period: DateRange
  customer_id: str
  days_until_trial_ends() → int | None

    Get days until trial ends, or None if not trialing.

  discount: AppliedDiscount | None
  ended_at: datetime | None
  has_ended() → bool

    Check if subscriptionn has permanently ended.

  id: str
  is_active() → bool

    Check if subscriptionn is in an active state.

  is_canceled() → bool

    Check if subscriptionn is canceled.

  is_past_due() → bool

    Check if subscriptionn has payment issues.

  is_paused() → bool

    Check if subscriptionn is paused.

  is_trialing() → bool

    Check if subscriptionn is in trial.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'cancel_at_period_end': FieldInfo(annotation=bool, required=False, default=False), 'canceled_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'current_period': FieldInfo(annotation=DateRange, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'discount': FieldInfo(annotation=Union[AppliedDiscount, NoneType], required=False, default=None), 'ended_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'pause_collection': FieldInfo(annotation=Union[PauseConfig, NoneType], required=False, default=None), 'plan_id': FieldInfo(annotation=str, required=True), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'quantity': FieldInfo(annotation=int, required=False, default=1), 'status': FieldInfo(annotation=SubscriptionStatus, required=False, default=<SubscriptionStatus.INCOMPLETE: 'incomplete'>), 'trial_end': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  pause_collection: PauseConfig | None
  plan_id: str
  provider_ref: ProviderReference
  quantity: int
  remove_discount() → None

    Remove discount from subscriptionn.

  schedule_cancellation() → None

    Schedule cancellation at period end.

  status: SubscriptionStatus
  trial_end: datetime | None
  unschedule_cancellation() → None

    Remove scheduled cancellation.

  updated_at: datetime
  will_cancel_at_period_end() → bool

    Check if subscriptionn is scheduled to cancel.

class subscriptionkore.core.models.subscription.SubscriptionStatus(*values)

  Bases: `StrEnum`

  Subscription status values.

  ACTIVE = 'active'
  CANCELED = 'canceled'
  EXPIRED = 'expired'
  INCOMPLETE = 'incomplete'
  INCOMPLETE_EXPIRED = 'incomplete_expired'
  PAST_DUE = 'past_due'
  PAUSED = 'paused'
  TRIALING = 'trialing'
  UNPAID = 'unpaid'

Customer domain model.

class subscriptionkore.core.models.customer.Address(*, line1: str | None = None, line2: str | None = None, city: str | None = None, state: str | None = None, postal_code: str | None = None, country: str | None = None)

  Bases: `BaseModel`

  Billing address.

  city: str | None
  country: str | None
  line1: str | None
  line2: str | None
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'city': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'country': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'line1': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'line2': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'postal_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'state': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  postal_code: str | None
  state: str | None

class subscriptionkore.core.models.customer.Customer(*, id: str = None, external_id: str, email: EmailStr, name: str | None = None, provider_refs: list[ProviderReference] = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Customer domain entity.

  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  billing_address: Address | None
  created_at: datetime
  email: EmailStr
  external_id: str
  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'billing_address': FieldInfo(annotation=Union[Address, NoneType], required=False, default=None), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'email': FieldInfo(annotation=EmailStr, required=True), 'external_id': FieldInfo(annotation=str, required=True), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'tax_info': FieldInfo(annotation=Union[TaxInfo, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str | None
  provider_refs: list[ProviderReference]
  tax_info: TaxInfo | None
  update(email: str | None = None, name: str | None = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict[str, Any] | None = None) → None

    Update customer fields.

  updated_at: datetime

class subscriptionkore.core.models.customer.TaxInfo(*, tax_id: str | None = None, tax_id_type: str | None = None, tax_exempt: bool = False)

  Bases: `BaseModel`

  Customer tax information.

  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'tax_exempt': FieldInfo(annotation=bool, required=False, default=False), 'tax_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'tax_id_type': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  tax_exempt: bool
  tax_id: str | None
  tax_id_type: str | None

Plan domain model.

class subscriptionkore.core.models.plan.Plan(*, id: str = None, product_id: str, name: str, description: str | None = None, provider_refs: list[ProviderReference] = None, price: Money, billing_period: BillingPeriod, trial_period_days: int | None = None, entitlements: list[PlanEntitlement] = None, active: bool = True, tier: int = 0, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Plan domain entity (a pricing tier for a product).

  active: bool
  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  billing_period: BillingPeriod
  created_at: datetime
  deactivate() → None

    Deactivate the plan.

  description: str | None
  entitlements: list[PlanEntitlement]
  get_entitlement_value(key: str) → bool | int | str | None

    Get entitlement value by key.

  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  is_downgrade_from(other: Plan) → bool

    Check if this plan is a downgrade from another.

  is_upgrade_from(other: Plan) → bool

    Check if this plan is an upgrade from another.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'active': FieldInfo(annotation=bool, required=False, default=True), 'billing_period': FieldInfo(annotation=BillingPeriod, required=True), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'entitlements': FieldInfo(annotation=list[PlanEntitlement], required=False, default_factory=list), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'price': FieldInfo(annotation=Money, required=True), 'product_id': FieldInfo(annotation=str, required=True), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'tier': FieldInfo(annotation=int, required=False, default=0, description='For upgrade/downgrade ordering'), 'trial_period_days': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  price: Money
  product_id: str
  provider_refs: list[ProviderReference]
  tier: int
  trial_period_days: int | None
  updated_at: datetime

class subscriptionkore.core.models.plan.PlanEntitlement(*, entitlement_id: str, entitlement_key: str, value: bool | int | str | None, value_type: EntitlementValueType)

  Bases: `BaseModel`

  Entitlement configuration for a plan.

  entitlement_id: str
  entitlement_key: str
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'entitlement_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'value': FieldInfo(annotation=Union[bool, int, str, NoneType], required=True), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  value: bool | int | str | None
  value_type: EntitlementValueType

Product domain model.

class subscriptionkore.core.models.product.Product(*, id: str = None, name: str, description: str | None = None, provider_refs: list[ProviderReference] = None, active: bool = True, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Product domain entity.

  activate() → None

    Activate the product.

  active: bool
  add_provider_ref(ref: ProviderReference) → None

    Add or update a provider reference.

  created_at: datetime
  deactivate() → None

    Deactivate the product.

  description: str | None
  get_provider_ref(provider_type: str) → ProviderReference | None

    Get provider reference for a specific provider.

  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'active': FieldInfo(annotation=bool, required=False, default=True), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'provider_refs': FieldInfo(annotation=list[ProviderReference], required=False, default_factory=list), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  provider_refs: list[ProviderReference]
  updated_at: datetime

Invoice domain model.

class subscriptionkore.core.models.invoice.Invoice(*, id: str = None, customer_id: str, subscriptionkore_id: str | None = None, provider_ref: ProviderReference, status: InvoiceStatus = InvoiceStatus.DRAFT, subtotal: Money, tax: Money = None, discount_amount: Money = None, total: Money, amount_paid: Money = None, amount_due: Money, currency: Currency = Currency.USD, line_items: list[InvoiceLineItem] = None, period: DateRange | None = None, due_date: datetime | None = None, paid_at: datetime | None = None, invoice_pdf_url: str | None = None, hosted_invoice_url: str | None = None, metadata: dict[str, Any] = None, created_at: datetime = None)

  Bases: `BaseModel`

  Invoice domain entity.

  amount_due: Money
  amount_paid: Money
  created_at: datetime
  currency: Currency
  customer_id: str
  discount_amount: Money
  due_date: datetime | None
  hosted_invoice_url: str | None
  id: str
  invoice_pdf_url: str | None
  is_open() → bool

    Check if invoice is open for payment.

  is_overdue() → bool

    Check if invoice is past due date.

  is_paid() → bool

    Check if invoice is fully paid.

  line_items: list[InvoiceLineItem]
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_due': FieldInfo(annotation=Money, required=True), 'amount_paid': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'currency': FieldInfo(annotation=Currency, required=False, default=<Currency.USD: 'USD'>), 'customer_id': FieldInfo(annotation=str, required=True), 'discount_amount': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'due_date': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'hosted_invoice_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'invoice_pdf_url': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'line_items': FieldInfo(annotation=list[InvoiceLineItem], required=False, default_factory=list), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'paid_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'period': FieldInfo(annotation=Union[DateRange, NoneType], required=False, default=None), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'status': FieldInfo(annotation=InvoiceStatus, required=False, default=<InvoiceStatus.DRAFT: 'draft'>), 'subscriptionkore_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'subtotal': FieldInfo(annotation=Money, required=True), 'tax': FieldInfo(annotation=Money, required=False, default_factory=<lambda>), 'total': FieldInfo(annotation=Money, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  paid_at: datetime | None
  period: DateRange | None
  provider_ref: ProviderReference
  remaining_balance() → Money

    Get remaining balance to be paid.

  status: InvoiceStatus
  subscriptionkore_id: str | None
  subtotal: Money
  tax: Money
  total: Money

class subscriptionkore.core.models.invoice.InvoiceLineItem(*, id: str = None, description: str, quantity: int = 1, unit_amount: Money, amount: Money, period: DateRange | None = None, proration: bool = False, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Line item on an invoice.

  amount: Money
  description: str
  id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'description': FieldInfo(annotation=str, required=True), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'period': FieldInfo(annotation=Union[DateRange, NoneType], required=False, default=None), 'proration': FieldInfo(annotation=bool, required=False, default=False), 'quantity': FieldInfo(annotation=int, required=False, default=1), 'unit_amount': FieldInfo(annotation=Money, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  period: DateRange | None
  proration: bool
  quantity: int
  unit_amount: Money

class subscriptionkore.core.models.invoice.InvoiceStatus(*values)

  Bases: `StrEnum`

  Invoice status values.

  DRAFT = 'draft'
  OPEN = 'open'
  PAID = 'paid'
  UNCOLLECTIBLE = 'uncollectible'
  VOID = 'void'

Payment event domain model.

class subscriptionkore.core.models.payment_event.PaymentEvent(*, id: str = None, provider_ref: ProviderReference, customer_id: str, subscriptionkore_id: str | None = None, invoice_id: str | None = None, event_type: PaymentEventType, amount: Money, status: PaymentStatus, failure_reason: str | None = None, failure_code: str | None = None, payment_method_type: str | None = None, payment_method_last4: str | None = None, occurred_at: datetime = None, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Payment event domain entity.

  amount: Money
  customer_id: str
  event_type: PaymentEventType
  failure_code: str | None
  failure_reason: str | None
  id: str
  invoice_id: str | None
  is_failed() → bool

    Check if payment failed.

  is_successful() → bool

    Check if payment succeeded.

  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_type': FieldInfo(annotation=PaymentEventType, required=True), 'failure_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'failure_reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_method_last4': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'payment_method_type': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'provider_ref': FieldInfo(annotation=ProviderReference, required=True), 'status': FieldInfo(annotation=PaymentStatus, required=True), 'subscriptionkore_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  payment_method_last4: str | None
  payment_method_type: str | None
  provider_ref: ProviderReference
  status: PaymentStatus
  subscriptionkore_id: str | None

class subscriptionkore.core.models.payment_event.PaymentEventType(*values)

  Bases: `StrEnum`

  Payment event types.

  PAYMENT_DISPUTED = 'payment_disputed'
  PAYMENT_FAILED = 'payment_failed'
  PAYMENT_REFUNDED = 'payment_refunded'
  PAYMENT_SUCCEEDED = 'payment_succeeded'

class subscriptionkore.core.models.payment_event.PaymentStatus(*values)

  Bases: `StrEnum`

  Payment status values.

  DISPUTED = 'disputed'
  FAILED = 'failed'
  PARTIALLY_REFUNDED = 'partially_refunded'
  PENDING = 'pending'
  REFUNDED = 'refunded'
  SUCCEEDED = 'succeeded'

Entitlement domain models.

class subscriptionkore.core.models.entitlement.CustomerEntitlement(*, customer_id: str, entitlement_key: str, current_value: bool | int | str, value_type: EntitlementValueType, source: EntitlementSource, expires_at: datetime | None = None, subscription_id: str | None = None, plan_id: str | None = None)

  Bases: `BaseModel`

  Resolved entitlement for a customer.

  as_bool() → bool

    Get value as boolean.

  as_int() → int | None

    Get value as integer (None for unlimited).

  current_value: bool | int | str
  customer_id: str
  entitlement_key: str
  expires_at: datetime | None
  is_boolean() → bool
  is_expired() → bool

    Check if entitlement has expired.

  is_numeric() → bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'current_value': FieldInfo(annotation=Union[bool, int, str], required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'expires_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'plan_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'source': FieldInfo(annotation=EntitlementSource, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  plan_id: str | None
  source: EntitlementSource
  subscription_id: str | None
  value_type: EntitlementValueType

class subscriptionkore.core.models.entitlement.Entitlement(*, id: str = None, key: str, name: str, description: str | None = None, value_type: EntitlementValueType, default_value: bool | int | str | None = None, metadata: dict[str, Any] = None, created_at: datetime = None, updated_at: datetime = None)

  Bases: `BaseModel`

  Entitlement definition entity.

  created_at: datetime
  default_value: bool | int | str | None
  description: str | None
  id: str
  key: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'default_value': FieldInfo(annotation=Union[bool, int, str, NoneType], required=False, default=None), 'description': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'key': FieldInfo(annotation=str, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'name': FieldInfo(annotation=str, required=True), 'updated_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  name: str
  updated_at: datetime
  value_type: EntitlementValueType

class subscriptionkore.core.models.entitlement.EntitlementOverride(*, id: str = None, customer_id: str, entitlement_key: str, value: bool | int | str, value_type: EntitlementValueType, reason: str | None = None, expires_at: datetime | None = None, created_by: str | None = None, created_at: datetime = None)

  Bases: `BaseModel`

  Manual entitlement override for a customer.

  created_at: datetime
  created_by: str | None
  customer_id: str
  entitlement_key: str
  expires_at: datetime | None
  id: str
  is_expired() → bool

    Check if override has expired.

  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'created_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'created_by': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'customer_id': FieldInfo(annotation=str, required=True), 'entitlement_key': FieldInfo(annotation=str, required=True), 'expires_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'value': FieldInfo(annotation=Union[bool, int, str], required=True), 'value_type': FieldInfo(annotation=EntitlementValueType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  reason: str | None
  value: bool | int | str
  value_type: EntitlementValueType

class subscriptionkore.core.models.entitlement.EntitlementSource(*values)

  Bases: `StrEnum`

  Source of an entitlement.

  DEFAULT = 'default'
  OVERRIDE = 'override'
  PLAN = 'plan'
  TRIAL = 'trial'

class subscriptionkore.core.models.entitlement.EntitlementValueType(*values)

  Bases: `StrEnum`

  Types of entitlement values.

  BOOLEAN = 'boolean'
  NUMERIC = 'numeric'
  STRING = 'string'
  UNLIMITED = 'unlimited'

## Value Objects

Value objects for the domain layer.

class subscriptionkore.core.models.value_objects.BillingPeriod(*, interval: Interval, interval_count: Annotated[int, Ge(ge=1)] = 1, anchor_date: datetime | None = None)

  Bases: `BaseModel`

  Billing period configuration.

  anchor_date: datetime | None
  property display_name: str
  interval: Interval
  interval_count: int
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'anchor_date': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'interval': FieldInfo(annotation=Interval, required=True), 'interval_count': FieldInfo(annotation=int, required=False, default=1, metadata=[Ge(ge=1)])}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  classmethod monthly() → BillingPeriod
  classmethod weekly() → BillingPeriod
  classmethod yearly() → BillingPeriod

class subscriptionkore.core.models.value_objects.Currency(*values)

  Bases: `StrEnum`

  ISO 4217 currency codes.

  AUD = 'AUD'
  BRL = 'BRL'
  CAD = 'CAD'
  CHF = 'CHF'
  EUR = 'EUR'
  GBP = 'GBP'
  INR = 'INR'
  JPY = 'JPY'
  MXN = 'MXN'
  USD = 'USD'

class subscriptionkore.core.models.value_objects.DateRange(*, start: datetime, end: datetime | None = None)

  Bases: `BaseModel`

  Date range with start and optional end.

  contains(dt: datetime) → bool
  end: datetime | None
  is_open_ended() → bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'end': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'start': FieldInfo(annotation=datetime, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  start: datetime
  validate_range() → Self

class subscriptionkore.core.models.value_objects.Interval(*values)

  Bases: `StrEnum`

  Billing interval types.

  DAY = 'day'
  MONTH = 'month'
  WEEK = 'week'
  YEAR = 'year'

class subscriptionkore.core.models.value_objects.Money(*, amount: Decimal, currency: Currency = Currency.USD)

  Bases: `BaseModel`

  Immutable monetary value with currency.

  amount: Decimal
  currency: Currency
  classmethod from_cents(cents: int, currency: Currency = Currency.USD) → Money

    Create Money from minor units (cents).

  is_negative() → bool
  is_positive() → bool
  is_zero() → bool
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Decimal, required=True, description='Amount in major currency units'), 'currency': FieldInfo(annotation=Currency, required=False, default=<Currency.USD: 'USD'>)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  classmethod normalize_amount(v: Any) → Decimal
  to_cents() → int

    Convert to minor units (cents).

  classmethod zero(currency: Currency = Currency.USD) → Money

class subscriptionkore.core.models.value_objects.ProviderReference(*, provider: ProviderType, external_id: str, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Reference to an entity in a payment provider.

  external_id: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'external_id': FieldInfo(annotation=str, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'provider': FieldInfo(annotation=ProviderType, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  provider: ProviderType

class subscriptionkore.core.models.value_objects.ProviderType(*values)

  Bases: `StrEnum`

  Supported payment providers.

  CHARGEBEE = 'chargebee'
  LEMONSQUEEZY = 'lemonsqueezy'
  PADDLE = 'paddle'
  STRIPE = 'stripe'

## Events

Domain events.

class subscriptionkore.core.events.CustomerCreated(*, event_id: str = None, event_type: str = 'CustomerCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, customer: Customer)

  Bases: `DomainEvent`

  Emitted when a customer is created.

  customer: Customer
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer': FieldInfo(annotation=Customer, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='CustomerCreated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime

class subscriptionkore.core.events.CustomerUpdated(*, event_id: str = None, event_type: str = 'CustomerUpdated', occurred_at: datetime = None, metadata: dict[str, Any] = None, customer: Customer, changed_fields: list[str])

  Bases: `DomainEvent`

  Emitted when a customer is updated.

  changed_fields: list[str]
  customer: Customer
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'changed_fields': FieldInfo(annotation=list[str], required=True), 'customer': FieldInfo(annotation=Customer, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='CustomerUpdated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime

class subscriptionkore.core.events.DomainEvent(*, event_id: str = None, event_type: str = '', occurred_at: datetime = None, metadata: dict[str, Any] = None)

  Bases: `BaseModel`

  Base class for all domain events.

  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPlanChanged'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime

class subscriptionkore.core.events.InvoiceCreated(*, event_id: str = None, event_type: str = 'InvoiceCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, invoice: Invoice, customer_id: str, subscription_id: str | None = None)

  Bases: `DomainEvent`

  Emitted when an invoice is created.

  customer_id: str
  event_id: str
  event_type: str
  invoice: Invoice
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='InvoiceCreated'), 'invoice': FieldInfo(annotation=Invoice, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscription_id: str | None

class subscriptionkore.core.events.InvoicePaid(*, event_id: str = None, event_type: str = 'InvoicePaid', occurred_at: datetime = None, metadata: dict[str, Any] = None, invoice: Invoice, customer_id: str, subscription_id: str | None = None, amount_paid: Money)

  Bases: `DomainEvent`

  Emitted when an invoice is paid.

  amount_paid: Money
  customer_id: str
  event_id: str
  event_type: str
  invoice: Invoice
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount_paid': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='InvoicePaid'), 'invoice': FieldInfo(annotation=Invoice, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscription_id: str | None

class subscriptionkore.core.events.PaymentFailed(*, event_id: str = None, event_type: str = 'PaymentFailed', occurred_at: datetime = None, metadata: dict[str, Any] = None, payment_event: PaymentEvent, customer_id: str, subscription_id: str | None = None, invoice_id: str | None = None, amount: Money, failure_reason: str | None = None, failure_code: str | None = None, attempt_count: int = 1)

  Bases: `DomainEvent`

  Emitted when a payment fails.

  amount: Money
  attempt_count: int
  customer_id: str
  event_id: str
  event_type: str
  failure_code: str | None
  failure_reason: str | None
  invoice_id: str | None
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'attempt_count': FieldInfo(annotation=int, required=False, default=1), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='PaymentFailed'), 'failure_code': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'failure_reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_event': FieldInfo(annotation=PaymentEvent, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  payment_event: PaymentEvent
  subscription_id: str | None

class subscriptionkore.core.events.PaymentSucceeded(*, event_id: str = None, event_type: str = 'PaymentSucceeded', occurred_at: datetime = None, metadata: dict[str, Any] = None, payment_event: PaymentEvent, customer_id: str, subscription_id: str | None = None, invoice_id: str | None = None, amount: Money)

  Bases: `DomainEvent`

  Emitted when a payment succeeds.

  amount: Money
  customer_id: str
  event_id: str
  event_type: str
  invoice_id: str | None
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'amount': FieldInfo(annotation=Money, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='PaymentSucceeded'), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'payment_event': FieldInfo(annotation=PaymentEvent, required=True), 'subscription_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  payment_event: PaymentEvent
  subscription_id: str | None

class subscriptionkore.core.events.SubscriptionActivated(*, event_id: str = None, event_type: str = 'SubscriptionActivated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore becomes active.

  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionActivated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionCanceled(*, event_id: str = None, event_type: str = 'SubscriptionCanceled', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str, immediate: bool, reason: str | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is canceled.

  customer_id: str
  event_id: str
  event_type: str
  immediate: bool
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionCanceled'), 'immediate': FieldInfo(annotation=bool, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'reason': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  plan_id: str
  reason: str | None
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionCreated(*, event_id: str = None, event_type: str = 'SubscriptionCreated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, plan_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is created.

  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionCreated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionPastDue(*, event_id: str = None, event_type: str = 'SubscriptionPastDue', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, invoice_id: str | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore becomes past due.

  customer_id: str
  event_id: str
  event_type: str
  invoice_id: str | None
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPastDue'), 'invoice_id': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionPaused(*, event_id: str = None, event_type: str = 'SubscriptionPaused', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, resumes_at: datetime | None = None)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is paused.

  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPaused'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'resumes_at': FieldInfo(annotation=Union[datetime, NoneType], required=False, default=None), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  resumes_at: datetime | None
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionPlanChanged(*, event_id: str = None, event_type: str = 'SubscriptionPlanChanged', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, previous_plan_id: str, new_plan_id: str, is_upgrade: bool)

  Bases: `DomainEvent`

  Emitted when subscriptionkore plan is changed.

  customer_id: str
  event_id: str
  event_type: str
  is_upgrade: bool
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionPlanChanged'), 'is_upgrade': FieldInfo(annotation=bool, required=True), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'new_plan_id': FieldInfo(annotation=str, required=True), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'previous_plan_id': FieldInfo(annotation=str, required=True), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  new_plan_id: str
  occurred_at: datetime
  previous_plan_id: str
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionResumed(*, event_id: str = None, event_type: str = 'SubscriptionResumed', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str)

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is resumed.

  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionResumed'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionTrialEnded(*, event_id: str = None, event_type: str = 'SubscriptionTrialEnded', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, converted: bool)

  Bases: `DomainEvent`

  Emitted when a trial ends.

  converted: bool
  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'converted': FieldInfo(annotation=bool, required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionTrialEnded'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscriptionkore: Subscription

class subscriptionkore.core.events.SubscriptionTrialStarted(*, event_id: str = None, event_type: str = 'SubscriptionTrialStarted', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, trial_end: datetime)

  Bases: `DomainEvent`

  Emitted when a trial starts.

  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionTrialStarted'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True), 'trial_end': FieldInfo(annotation=datetime, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscriptionkore: Subscription
  trial_end: datetime

class subscriptionkore.core.events.SubscriptionUpdated(*, event_id: str = None, event_type: str = 'SubscriptionUpdated', occurred_at: datetime = None, metadata: dict[str, Any] = None, subscriptionkore: Subscription, customer_id: str, changed_fields: list[str])

  Bases: `DomainEvent`

  Emitted when a subscriptionkore is updated.

  changed_fields: list[str]
  customer_id: str
  event_id: str
  event_type: str
  metadata: dict[str, Any]
  model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

    A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

  model_config: ClassVar[ConfigDict] = {'frozen': True}

    Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

  model_fields: ClassVar[Dict[str, FieldInfo]] = {'changed_fields': FieldInfo(annotation=list[str], required=True), 'customer_id': FieldInfo(annotation=str, required=True), 'event_id': FieldInfo(annotation=str, required=False, default_factory=<lambda>), 'event_type': FieldInfo(annotation=str, required=False, default='SubscriptionUpdated'), 'metadata': FieldInfo(annotation=dict[str, Any], required=False, default_factory=dict), 'occurred_at': FieldInfo(annotation=datetime, required=False, default_factory=builtin_function_or_method), 'subscriptionkore': FieldInfo(annotation=Subscription, required=True)}

    Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

    This replaces Model.__fields__ from Pydantic V1.

  occurred_at: datetime
  subscriptionkore: Subscription

## Exceptions

Domain exceptions.

exception subscriptionkore.core.exceptions.ConfigurationError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for configuration errors.

exception subscriptionkore.core.exceptions.DomainError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for domain errors.

exception subscriptionkore.core.exceptions.DuplicateEntityError(entity_type: str, identifier: str)

  Bases: `DomainError`

  Raised when attempting to create a duplicate entity.

exception subscriptionkore.core.exceptions.EntitlementError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for entitlement errors.

exception subscriptionkore.core.exceptions.EntitlementNotFoundError(key: str)

  Bases: `EntitlementError`

  Raised when an entitlement is not found.

exception subscriptionkore.core.exceptions.EntityNotFoundError(entity_type: str, entity_id: str)

  Bases: `DomainError`

  Raised when an entity is not found.

exception subscriptionkore.core.exceptions.InvalidConfigurationError(message: str, details: dict[str, Any] | None = None)

  Bases: `ConfigurationError`

  Raised when configuration is invalid.

exception subscriptionkore.core.exceptions.InvalidStateTransitionError(from_state: SubscriptionStatus, to_state: SubscriptionStatus, reason: str | None = None)

  Bases: `DomainError`

  Raised when an invalid state transition is attempted.

exception subscriptionkore.core.exceptions.MissingProviderCredentialsError(provider: str, missing_fields: list[str])

  Bases: `ConfigurationError`

  Raised when provider credentials are missing.

exception subscriptionkore.core.exceptions.ProviderAPIError(message: str, provider: str, status_code: int, provider_message: str | None = None, provider_code: str | None = None)

  Bases: `ProviderError`

  Raised for non-recoverable API errors from providers.

exception subscriptionkore.core.exceptions.ProviderAuthenticationError(provider: str, message: str | None = None)

  Bases: `ProviderError`

  Raised when authentication fails. Non-recoverable.

exception subscriptionkore.core.exceptions.ProviderError(message: str, provider: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for provider errors.

exception subscriptionkore.core.exceptions.ProviderNetworkError(provider: str, original_error: Exception)

  Bases: `ProviderError`

  Raised for network errors. Recoverable with retry.

exception subscriptionkore.core.exceptions.ProviderRateLimitError(provider: str, retry_after: int | None = None)

  Bases: `ProviderError`

  Raised when provider rate limit is exceeded. Recoverable with retry.

exception subscriptionkore.core.exceptions.RepositoryError(operation: str, entity_type: str, original_error: Exception)

  Bases: `SubscriptionKoreError`

  Raised when a repository operation fails.

exception subscriptionkore.core.exceptions.SubscriptionKoreError(message: str, details: dict[str, Any] | None = None)

  Bases: `Exception`

  Base exception for all subscriptionkore errors.

exception subscriptionkore.core.exceptions.UsageLimitExceededError(entitlement_key: str, limit: int, current_usage: int, requested: int)

  Bases: `EntitlementError`

  Raised when a usage limit is exceeded.

exception subscriptionkore.core.exceptions.ValidationError(field: str, message: str)

  Bases: `DomainError`

  Raised when validation fails.

exception subscriptionkore.core.exceptions.WebhookError(message: str, details: dict[str, Any] | None = None)

  Bases: `SubscriptionKoreError`

  Base class for webhook errors.

exception subscriptionkore.core.exceptions.WebhookPayloadInvalidError(provider: str, reason: str)

  Bases: `WebhookError`

  Raised when webhook payload cannot be parsed.

exception subscriptionkore.core.exceptions.WebhookProcessingError(event_id: str, reason: str)

  Bases: `WebhookError`

  Raised when webhook processing fails.

exception subscriptionkore.core.exceptions.WebhookSignatureInvalidError(provider: str)

  Bases: `WebhookError`

  Raised when webhook signature verification fails.

## Adapters

Stripe adapter.

class subscriptionkore.adapters.stripe.StripeAdapter(config: StripeConfig)

  Bases: `PaymentProviderPort`

  Stripe payment provider implementation.

  BASE_URL = 'https://api.stripe.com/v1'
  INVOICE_STATUS_MAP = {'draft': InvoiceStatus.DRAFT, 'open': InvoiceStatus.OPEN, 'paid': InvoiceStatus.PAID, 'uncollectible': InvoiceStatus.UNCOLLECTIBLE, 'void': InvoiceStatus.VOID}
  STATUS_MAP = {'active': SubscriptionStatus.ACTIVE, 'canceled': SubscriptionStatus.CANCELED, 'incomplete': SubscriptionStatus.INCOMPLETE, 'incomplete_expired': SubscriptionStatus.INCOMPLETE_EXPIRED, 'past_due': SubscriptionStatus.PAST_DUE, 'paused': SubscriptionStatus.PAUSED, 'trialing': SubscriptionStatus.TRIALING, 'unpaid': SubscriptionStatus.UNPAID}
  async apply_discount(subscriptionkore_provider_ref: ProviderReference, discount: DiscountRequest) → Subscription

    Apply a discount to a subscriptionkore.

  async cancel_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, immediate: bool = False) → Subscription

    Cancel a subscriptionkore.

  property capabilities: ProviderCapabilities

    Return provider capabilities.

  async change_plan(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → Subscription

    Change subscriptionkore plan (upgrade/downgrade).

  async close() → None
  async create_checkout_session(request: CheckoutRequest, plan_provider_ref: ProviderReference, customer_provider_ref: ProviderReference | None = None) → CheckoutSession

    Create a checkout session.

  async create_customer(customer: Customer) → ProviderReference

    Create a customer in the provider.

  async create_portal_session(customer_provider_ref: ProviderReference, return_url: str) → PortalSession

    Create a customer portal session.

  async create_subscriptionkore(request: CreateSubscriptionRequest, customer_provider_ref: ProviderReference, plan_provider_ref: ProviderReference) → Subscription

    Create a subscriptionkore.

  async delete_customer(provider_ref: ProviderReference) → None

    Delete a customer from the provider.

  async get_customer(provider_ref: ProviderReference) → Customer

    Get a customer from the provider.

  async get_invoice(provider_ref: ProviderReference) → Invoice

    Get an invoice from the provider.

  async get_subscriptionkore(provider_ref: ProviderReference) → Subscription

    Get a subscriptionkore from the provider.

  async get_upcoming_invoice(subscriptionkore_provider_ref: ProviderReference) → Invoice | None

    Get upcoming invoice for a subscriptionkore.

  async list_invoices(customer_provider_ref: ProviderReference, limit: int = 10, starting_after: str | None = None) → list[Invoice]

    List invoices for a customer.

  async parse_webhook(payload: bytes, headers: dict[str, str]) → ProviderWebhookEvent

    Parse Stripe webhook payload.

  async pause_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, resumes_at: datetime | None = None) → Subscription

    Pause a subscriptionkore.

  async preview_plan_change(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → ChangePreview

    Preview plan change costs.

  property provider_type: ProviderType

    Return the provider type.

  async remove_discount(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Remove discount from a subscriptionkore.

  async resume_subscriptionkore(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Resume a paused subscriptionkore.

  async sync_plans(product_provider_ref: ProviderReference) → list[Plan]

    Sync all plans for a product from provider.

  async sync_products() → list[Product]

    Sync all products from provider.

  async update_customer(customer: Customer) → None

    Update a customer in the provider.

  async update_subscriptionkore(request: UpdateSubscriptionRequest, subscriptionkore_provider_ref: ProviderReference) → Subscription

    Update a subscriptionkore.

  async verify_webhook(payload: bytes, headers: dict[str, str]) → bool

    Verify Stripe webhook signature.

Chargebee adapter.

class subscriptionkore.adapters.chargebee.ChargebeeAdapter(config: ChargebeeConfig)

  Bases: `PaymentProviderPort`

  Chargebee payment provider implementation.

  Implements the Chargebee API for subscriptionkore management. Reference: https://apidocs.eu.chargebee. com/docs/api/

  INVOICE_STATUS_MAP = {'not_paid': InvoiceStatus.OPEN, 'paid': InvoiceStatus.PAID, 'payment_due': InvoiceStatus.OPEN, 'pending': InvoiceStatus.DRAFT, 'posted': InvoiceStatus.OPEN, 'voided': InvoiceStatus.VOID}
  STATUS_MAP = {'active': SubscriptionStatus.ACTIVE, 'cancelled': SubscriptionStatus.CANCELED, 'future': SubscriptionStatus.INCOMPLETE, 'in_trial': SubscriptionStatus.TRIALING, 'non_renewing': SubscriptionStatus.ACTIVE, 'paused': SubscriptionStatus.PAUSED}
  async apply_discount(subscriptionkore_provider_ref: ProviderReference, discount: DiscountRequest) → Subscription

    Apply a discount to a subscriptionkore.

  async cancel_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, immediate: bool = False) → Subscription

    Cancel a subscriptionkore.

  property capabilities: ProviderCapabilities

    Return provider capabilities.

  async change_plan(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → Subscription

    Change subscriptionkore plan (upgrade/downgrade).

  async close() → None
  async create_checkout_session(request: CheckoutRequest, plan_provider_ref: ProviderReference, customer_provider_ref: ProviderReference | None = None) → CheckoutSession

    Create a checkout session.

  async create_customer(customer: Customer) → ProviderReference

    Create a customer in the provider.

  async create_portal_session(customer_provider_ref: ProviderReference, return_url: str) → PortalSession

    Create a customer portal session.

  async create_subscriptionkore(request: CreateSubscriptionRequest, customer_provider_ref: ProviderReference, plan_provider_ref: ProviderReference) → Subscription

    Create a subscriptionkore.

  async delete_customer(provider_ref: ProviderReference) → None

    Delete a customer from the provider.

  async get_customer(provider_ref: ProviderReference) → Customer

    Get a customer from the provider.

  async get_invoice(provider_ref: ProviderReference) → Invoice

    Get an invoice from the provider.

  async get_subscriptionkore(provider_ref: ProviderReference) → Subscription

    Get a subscriptionkore from the provider.

  async get_upcoming_invoice(subscriptionkore_provider_ref: ProviderReference) → Invoice | None

    Get upcoming invoice for a subscriptionkore.

  async list_invoices(customer_provider_ref: ProviderReference, limit: int = 10, starting_after: str | None = None) → list[Invoice]

    List invoices for a customer.

  async parse_webhook(payload: bytes, headers: dict[str, str]) → ProviderWebhookEvent

    Parse Chargebee webhook payload.

  async pause_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, resumes_at: datetime | None = None) → Subscription

    Pause a subscriptionkore.

  async preview_plan_change(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → ChangePreview

    Preview plan change costs.

  property provider_type: ProviderType

    Return the provider type.

  async remove_discount(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Remove discount from a subscriptionkore.

  async resume_subscriptionkore(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Resume a paused subscriptionkore.

  async sync_plans(product_provider_ref: ProviderReference) → list[Plan]

    Sync all plans for a product from provider.

  async sync_products() → list[Product]

    Sync all products from provider.

  async update_customer(customer: Customer) → None

    Update a customer in the provider.

  async update_subscriptionkore(request: UpdateSubscriptionRequest, subscriptionkore_provider_ref: ProviderReference) → Subscription

    Update a subscriptionkore.

  async verify_webhook(payload: bytes, headers: dict[str, str]) → bool

    Verify Chargebee webhook using basic auth.

Paddle adapter.

class subscriptionkore.adapters.paddle.PaddleAdapter(config: PaddleConfig)

  Bases: `PaymentProviderPort`

  Paddle Billing payment provider implementation.

  Implements the Paddle Billing API (v1) for subscriptionkore management. Reference: https://developer.paddle.com/api-reference/overview

  STATUS_MAP = {'active': SubscriptionStatus.ACTIVE, 'canceled': SubscriptionStatus.CANCELED, 'past_due': SubscriptionStatus.PAST_DUE, 'paused': SubscriptionStatus.PAUSED, 'trialing': SubscriptionStatus.TRIALING}
  async apply_discount(subscriptionkore_provider_ref: ProviderReference, discount: DiscountRequest) → Subscription

    Apply a discount to a subscriptionkore.

  async cancel_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, immediate: bool = False) → Subscription

    Cancel a subscriptionkore.

  property capabilities: ProviderCapabilities

    Return provider capabilities.

  async change_plan(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → Subscription

    Change subscriptionkore plan (upgrade/downgrade).

  async close() → None
  async create_checkout_session(request: CheckoutRequest, plan_provider_ref: ProviderReference, customer_provider_ref: ProviderReference | None = None) → CheckoutSession

    Create a checkout session.

  async create_customer(customer: Customer) → ProviderReference

    Create a customer in the provider.

  async create_portal_session(customer_provider_ref: ProviderReference, return_url: str) → PortalSession

    Create a customer portal session.

  async create_subscriptionkore(request: CreateSubscriptionRequest, customer_provider_ref: ProviderReference, plan_provider_ref: ProviderReference) → Subscription

    Create a subscriptionkore in Paddle.

    Note: Paddle subscriptionkores are typically created through checkout. This method creates a subscriptionkore directly via API.

  async delete_customer(provider_ref: ProviderReference) → None

    Delete a customer from the provider.

  async get_customer(provider_ref: ProviderReference) → Customer

    Get a customer from the provider.

  async get_invoice(provider_ref: ProviderReference) → Invoice

    Get an invoice from the provider.

  async get_subscriptionkore(provider_ref: ProviderReference) → Subscription

    Get a subscriptionkore from the provider.

  async get_upcoming_invoice(subscriptionkore_provider_ref: ProviderReference) → Invoice | None

    Get upcoming invoice for a subscriptionkore.

  async list_invoices(customer_provider_ref: ProviderReference, limit: int = 10, starting_after: str | None = None) → list[Invoice]

    List invoices for a customer.

  async parse_webhook(payload: bytes, headers: dict[str, str]) → ProviderWebhookEvent

    Parse Paddle webhook payload.

  async pause_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, resumes_at: datetime | None = None) → Subscription

    Pause a subscriptionkore.

  async preview_plan_change(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → ChangePreview

    Preview plan change costs.

  property provider_type: ProviderType

    Return the provider type.

  async remove_discount(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Remove discount from a subscriptionkore.

  async resume_subscriptionkore(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Resume a paused subscriptionkore.

  async sync_plans(product_provider_ref: ProviderReference) → list[Plan]

    Sync all plans for a product from provider.

  async sync_products() → list[Product]

    Sync all products from provider.

  async update_customer(customer: Customer) → None

    Update a customer in the provider.

  async update_subscriptionkore(request: UpdateSubscriptionRequest, subscriptionkore_provider_ref: ProviderReference) → Subscription

    Update a subscriptionkore.

  async verify_webhook(payload: bytes, headers: dict[str, str]) → bool

    Verify Paddle webhook signature.

LemonSqueezy adapter.

class subscriptionkore.adapters.lemonsqueezy.LemonSqueezyAdapter(config: LemonSqueezyConfig)

  Bases: `PaymentProviderPort`

  LemonSqueezy payment provider implementation.

  Implements the LemonSqueezy API for subscriptionkore management. Reference: https://docs.lemonsqueezy.com/api

  BASE_URL = 'https://api.lemonsqueezy.com/v1'
  STATUS_MAP = {'active': SubscriptionStatus.ACTIVE, 'cancelled': SubscriptionStatus.CANCELED, 'expired': SubscriptionStatus.EXPIRED, 'on_trial': SubscriptionStatus.TRIALING, 'past_due': SubscriptionStatus.PAST_DUE, 'paused': SubscriptionStatus.PAUSED, 'unpaid': SubscriptionStatus.UNPAID}
  async apply_discount(subscriptionkore_provider_ref: ProviderReference, discount: DiscountRequest) → Subscription

    Apply a discount to a subscriptionkore.

  async cancel_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, immediate: bool = False) → Subscription

    Cancel a subscriptionkore.

  property capabilities: ProviderCapabilities

    Return provider capabilities.

  async change_plan(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → Subscription

    Change subscriptionkore plan (upgrade/downgrade).

  async close() → None
  async create_checkout_session(request: CheckoutRequest, plan_provider_ref: ProviderReference, customer_provider_ref: ProviderReference | None = None) → CheckoutSession

    Create a checkout session.

  async create_customer(customer: Customer) → ProviderReference

    Create a customer in the provider.

  async create_portal_session(customer_provider_ref: ProviderReference, return_url: str) → PortalSession

    Create a customer portal session.

  async create_subscriptionkore(request: CreateSubscriptionRequest, customer_provider_ref: ProviderReference, plan_provider_ref: ProviderReference) → Subscription

    Create a subscriptionkore.

  async delete_customer(provider_ref: ProviderReference) → None

    Delete a customer from the provider.

  async get_customer(provider_ref: ProviderReference) → Customer

    Get a customer from the provider.

  async get_invoice(provider_ref: ProviderReference) → Invoice

    Get an invoice from the provider.

  async get_subscriptionkore(provider_ref: ProviderReference) → Subscription

    Get a subscriptionkore from the provider.

  async get_upcoming_invoice(subscriptionkore_provider_ref: ProviderReference) → Invoice | None

    Get upcoming invoice for a subscriptionkore.

  async list_invoices(customer_provider_ref: ProviderReference, limit: int = 10, starting_after: str | None = None) → list[Invoice]

    List invoices for a customer.

  async parse_webhook(payload: bytes, headers: dict[str, str]) → ProviderWebhookEvent

    Parse LemonSqueezy webhook payload.

  async pause_subscriptionkore(subscriptionkore_provider_ref: ProviderReference, resumes_at: datetime | None = None) → Subscription

    Pause a subscriptionkore.

  async preview_plan_change(request: ChangePlanRequest, subscriptionkore_provider_ref: ProviderReference, new_plan_provider_ref: ProviderReference) → ChangePreview

    Preview plan change costs.

  property provider_type: ProviderType

    Return the provider type.

  async remove_discount(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Remove discount from a subscriptionkore.

  async resume_subscriptionkore(subscriptionkore_provider_ref: ProviderReference) → Subscription

    Resume a paused subscriptionkore.

  async sync_plans(product_provider_ref: ProviderReference) → list[Plan]

    Sync all plans for a product from provider.

  async sync_products() → list[Product]

    Sync all products from provider.

  async update_customer(customer: Customer) → None

    Update a customer in the provider.

  async update_subscriptionkore(request: UpdateSubscriptionRequest, subscriptionkore_provider_ref: ProviderReference) → Subscription

    Update a subscriptionkore.

  async verify_webhook(payload: bytes, headers: dict[str, str]) → bool

    Verify LemonSqueezy webhook signature.

## Services

Application services.

class subscriptionkore.services.CustomerManager(customer_repo: CustomerRepository, provider: PaymentProviderPort, event_bus: EventBusPort)

  Bases: `object`

  Manages customer lifecycle operations.

  Provides a unified interface for customer operations across providers.

  async create(external_id: str, email: str, name: str | None = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict | None = None, sync_to_provider: bool = True) → Customer

    Create a new customer.

    Parameters:

      - external_id – Your application’s user ID

      - email – Customer email

      - name – Customer name

      - tax_info – Tax information

      - billing_address – Billing address

      - metadata – Additional metadata

      - sync_to_provider – Whether to create in payment provider

    Returns:

      Created customer

    Raises:

      DuplicateEntityError – If customer with external_id exists

  async delete(customer_id: str, delete_from_provider: bool = True) → bool

    Delete a customer.

    Parameters:

      - customer_id – Customer ID

      - delete_from_provider – Whether to delete from payment provider

    Returns:

      True if deleted

  async get(customer_id: str) → Customer

    Get customer by internal ID.

  async get_by_external_id(external_id: str) → Customer

    Get customer by external (application) ID.

  async get_or_create(external_id: str, email: str, name: str | None = None, sync_to_provider: bool = True) → tuple[Customer, bool]

    Get existing customer or create new one.

    Returns:

      Tuple of (customer, created) where created is True if new

  async list(limit: int = 100, offset: int = 0) → list[Customer]

    List customers with pagination.

  async sync_to_provider(customer_id: str, provider: ProviderType | None = None) → Customer

    Sync customer to payment provider.

    Creates customer in provider if not exists, or updates if exists.

  async update(customer_id: str, email: str | None = None, name: str | None = None, tax_info: TaxInfo | None = None, billing_address: Address | None = None, metadata: dict | None = None, sync_to_provider: bool = True) → Customer

    Update customer information.

class subscriptionkore.services.EntitlementService(entitlement_repo: EntitlementRepository, override_repo: EntitlementOverrideRepository, subscriptionkore_repo: SubscriptionRepository, plan_repo: PlanRepository, cache: CachePort | None = None, cache_ttl: int = 300)

  Bases: `object`

  Resolves and manages customer entitlements.

  Entitlements are derived from: 1. Customer-level overrides (highest priority) 2. Active subscriptionkore plan entitlements 3. Trial entitlements 4. Default entitlements (lowest priority)

  async check(customer_id: str, entitlement_key: str) → CustomerEntitlement

    Check a specific entitlement for a customer.

    Parameters:

      - customer_id – Customer ID

      - entitlement_key – Entitlement key to check

    Returns:

      Resolved CustomerEntitlement

    Raises:

      EntitlementNotFoundError – If entitlement key doesn’t exist

  async check_all(customer_id: str) → list[CustomerEntitlement]

    Get all resolved entitlements for a customer.

    Results are cached for performance.

  async check_many(customer_id: str, entitlement_keys: list[str]) → dict[str, CustomerEntitlement]

    Check multiple entitlements at once.

  async check_within_limit(customer_id: str, entitlement_key: str, current_usage: int, requested: int = 1) → tuple[bool, int | None]

    Check if usage is within limit.

    Parameters:

      - customer_id – Customer ID

      - entitlement_key – Entitlement key

      - current_usage – Current usage count

      - requested – Additional usage being requested

    Returns:

      Tuple of (within_limit, remaining) remaining is None for unlimited

  async enforce_limit(customer_id: str, entitlement_key: str, current_usage: int, requested: int = 1) → int | None

    Enforce usage limit, raising exception if exceeded.

    Parameters:

      - customer_id – Customer ID

      - entitlement_key – Entitlement key

      - current_usage – Current usage count

      - requested – Additional usage being requested

    Returns:

      Remaining quota (None for unlimited)

    Raises:

      UsageLimitExceededError – If limit would be exceeded

  async get_limit(customer_id: str, entitlement_key: str) → int | None

    Get numeric limit for an entitlement.

    Returns None for unlimited entitlements.

  async grant_override(customer_id: str, entitlement_key: str, value: bool | int | str, expires_at: datetime | None = None, reason: str | None = None, created_by: str | None = None) → EntitlementOverride

    Grant an entitlement override to a customer.

    Parameters:

      - customer_id – Customer ID

      - entitlement_key – Entitlement key

      - value – Override value

      - expires_at – When override expires (None for permanent)

      - reason – Reason for override

      - created_by – Who created the override

    Returns:

      Created override

  async has_access(customer_id: str, entitlement_key: str) → bool

    Check if customer has access to a feature.

  async invalidate(customer_id: str) → None

    Invalidate entitlement cache for a customer.

  async invalidate_all() → None

    Invalidate all entitlement caches.

  async list_overrides(customer_id: str, include_expired: bool = False) → list[EntitlementOverride]

    List all overrides for a customer.

  async revoke_override(customer_id: str, entitlement_key: str) → bool

    Revoke an entitlement override.

    Returns:

      True if override was deleted

class subscriptionkore.services.SubscriptionManager(subscriptionkore_repo: SubscriptionRepository, customer_repo: CustomerRepository, plan_repo: PlanRepository, provider: PaymentProviderPort, event_bus: EventBusPort)

  Bases: `object`

  Manages subscriptionkore lifecycle operations.

  Provides a unified interface for subscriptionkore operations across providers.

  async apply_discount(subscriptionkore_id: str, coupon_code: str) → Subscription

    Apply a discount to a subscriptionkore.

  async cancel(subscriptionkore_id: str, immediate: bool = False, reason: str | None = None) → Subscription

    Cancel a subscriptionkore.

    Parameters:

      - subscriptionkore_id – Subscription ID

      - immediate – If True, cancel immediately. If False, cancel at period end.

      - reason – Optional cancellation reason

    Returns:

      Updated subscriptionkore

  async change_plan(subscriptionkore_id: str, new_plan_id: str, proration_behavior: ProrationBehavior = ProrationBehavior.CREATE_PRORATIONS) → Subscription

    Change subscriptionkore plan (upgrade/downgrade).

    Parameters:

      - subscriptionkore_id – Subscription ID

      - new_plan_id – New plan ID

      - proration_behavior – How to handle proration

    Returns:

      Updated subscriptionkore

  async create(customer_id: str, plan_id: str, quantity: int = 1, trial_period_days: int | None = None, coupon_code: str | None = None, metadata: dict | None = None) → Subscription

    Create a new subscriptionkore.

    Parameters:

      - customer_id – Internal customer ID

      - plan_id – Internal plan ID

      - quantity – Subscription quantity

      - trial_period_days – Override trial period (None uses plan default)

      - coupon_code – Optional coupon code to apply

      - metadata – Additional metadata

    Returns:

      Created subscriptionkore

    Raises:

      EntityNotFoundError – If customer or plan not found

  async get(subscriptionkore_id: str) → Subscription

    Get subscriptionkore by ID.

  async get_active_by_customer(customer_id: str) → list[Subscription]

    Get active subscriptionkores for a customer.

  async get_by_customer(customer_id: str, include_canceled: bool = False) → list[Subscription]

    Get all subscriptionkores for a customer.

  async pause(subscriptionkore_id: str, resumes_at: datetime | None = None) → Subscription

    Pause a subscriptionkore.

  async preview_plan_change(subscriptionkore_id: str, new_plan_id: str, proration_behavior: ProrationBehavior = ProrationBehavior.CREATE_PRORATIONS) → ChangePreview

    Preview costs for a plan change.

  async reactivate(subscriptionkore_id: str) → Subscription

    Reactivate a subscriptionkore that was scheduled to cancel.

    Removes the cancel_at_period_end flag.

  async remove_discount(subscriptionkore_id: str) → Subscription

    Remove discount from a subscriptionkore.

  async resume(subscriptionkore_id: str) → Subscription

    Resume a paused subscriptionkore.

  async update(subscriptionkore_id: str, quantity: int | None = None, metadata: dict | None = None) → Subscription

    Update subscriptionkore quantity or metadata.

class subscriptionkore.services.WebhookProcessor(providers: dict[ProviderType, PaymentProviderPort], subscriptionkore_repo: SubscriptionRepository, customer_repo: CustomerRepository, plan_repo: PlanRepository, invoice_repo: InvoiceRepository, payment_event_repo: PaymentEventRepository, processed_event_repo: ProcessedEventRepository, event_bus: EventBusPort, entitlement_service: EntitlementService)

  Bases: `object`

  Processes webhooks from payment providers.

  Responsibilities: - Verify webhook signatures - Parse provider-specific payloads - Normalize to canonical event format - Apply state changes - Emit domain events - Ensure idempotency

  async process(provider: str, payload: bytes, headers: dict[str, str]) → WebhookResult

    Process a webhook from a payment provider.

    Parameters:

      - provider – Provider name (e.g., “stripe”, “paddle”)

      - payload – Raw webhook payload bytes

      - headers – HTTP headers from webhook request

    Returns:

      WebhookResult with processing outcome

    Raises:

      - WebhookSignatureInvalidError – If signature verification fails

      - WebhookPayloadInvalidError – If payload cannot be parsed

      - WebhookProcessingError – If processing fails

## Integrations

Framework integrations.