1325 lines
44 KiB
Python
1325 lines
44 KiB
Python
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
|
|
|
|
from __future__ import annotations
|
|
from autumn_sdk.types import (
|
|
BaseModel,
|
|
Nullable,
|
|
OptionalNullable,
|
|
UNSET,
|
|
UNSET_SENTINEL,
|
|
UnrecognizedStr,
|
|
)
|
|
from autumn_sdk.utils import FieldMetadata, HeaderMetadata
|
|
import pydantic
|
|
from pydantic import model_serializer
|
|
from typing import List, Literal, Optional, Union
|
|
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
|
|
|
|
|
|
class CreatePlanGlobalsTypedDict(TypedDict):
|
|
x_api_version: NotRequired[str]
|
|
|
|
|
|
class CreatePlanGlobals(BaseModel):
|
|
x_api_version: Annotated[
|
|
Optional[str],
|
|
pydantic.Field(alias="x-api-version"),
|
|
FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
|
|
] = "2.1"
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["x-api-version"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanPriceIntervalRequest = Literal[
|
|
"one_off",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
]
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
|
|
|
|
class CreatePlanPriceRequestTypedDict(TypedDict):
|
|
r"""Base recurring price for the plan. Omit for free or usage-only plans."""
|
|
|
|
amount: float
|
|
r"""Base price amount for the plan."""
|
|
interval: CreatePlanPriceIntervalRequest
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
|
|
class CreatePlanPriceRequest(BaseModel):
|
|
r"""Base recurring price for the plan. Omit for free or usage-only plans."""
|
|
|
|
amount: float
|
|
r"""Base price amount for the plan."""
|
|
|
|
interval: CreatePlanPriceIntervalRequest
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
|
|
interval_count: Optional[float] = None
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["interval_count"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanResetIntervalRequest = Literal[
|
|
"one_off",
|
|
"minute",
|
|
"hour",
|
|
"day",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
]
|
|
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
|
|
|
|
|
|
class CreatePlanResetRequestTypedDict(TypedDict):
|
|
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
|
|
|
|
interval: CreatePlanResetIntervalRequest
|
|
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals between resets. Defaults to 1."""
|
|
|
|
|
|
class CreatePlanResetRequest(BaseModel):
|
|
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
|
|
|
|
interval: CreatePlanResetIntervalRequest
|
|
r"""Interval at which balance resets (e.g. 'month', 'year'). For consumable features only."""
|
|
|
|
interval_count: Optional[float] = None
|
|
r"""Number of intervals between resets. Defaults to 1."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["interval_count"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanToRequestTypedDict = TypeAliasType(
|
|
"CreatePlanToRequestTypedDict", Union[float, str]
|
|
)
|
|
|
|
|
|
CreatePlanToRequest = TypeAliasType("CreatePlanToRequest", Union[float, str])
|
|
|
|
|
|
class CreatePlanTierRequestTypedDict(TypedDict):
|
|
to: CreatePlanToRequestTypedDict
|
|
amount: float
|
|
flat_amount: NotRequired[Nullable[float]]
|
|
|
|
|
|
class CreatePlanTierRequest(BaseModel):
|
|
to: CreatePlanToRequest
|
|
|
|
amount: float
|
|
|
|
flat_amount: OptionalNullable[float] = UNSET
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["flat_amount"])
|
|
nullable_fields = set(["flat_amount"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanTierBehaviorRequest = Literal[
|
|
"graduated",
|
|
"volume",
|
|
]
|
|
|
|
|
|
CreatePlanItemPriceIntervalRequest = Literal[
|
|
"one_off",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
]
|
|
r"""Billing interval. For consumable features, should match reset.interval."""
|
|
|
|
|
|
CreatePlanBillingMethodRequest = Literal[
|
|
"prepaid",
|
|
"usage_based",
|
|
]
|
|
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
|
|
|
|
|
|
class CreatePlanItemPriceRequestTypedDict(TypedDict):
|
|
r"""Pricing for usage beyond included units. Omit for free features."""
|
|
|
|
interval: CreatePlanItemPriceIntervalRequest
|
|
r"""Billing interval. For consumable features, should match reset.interval."""
|
|
billing_method: CreatePlanBillingMethodRequest
|
|
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
|
|
amount: NotRequired[float]
|
|
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
|
|
tiers: NotRequired[List[CreatePlanTierRequestTypedDict]]
|
|
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
|
|
tier_behavior: NotRequired[CreatePlanTierBehaviorRequest]
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
billing_units: NotRequired[float]
|
|
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
|
|
max_purchase: NotRequired[float]
|
|
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
|
|
|
|
|
|
class CreatePlanItemPriceRequest(BaseModel):
|
|
r"""Pricing for usage beyond included units. Omit for free features."""
|
|
|
|
interval: CreatePlanItemPriceIntervalRequest
|
|
r"""Billing interval. For consumable features, should match reset.interval."""
|
|
|
|
billing_method: CreatePlanBillingMethodRequest
|
|
r"""'prepaid' for upfront payment (seats), 'usage_based' for pay-as-you-go."""
|
|
|
|
amount: Optional[float] = None
|
|
r"""Price per billing_units after included usage. Either 'amount' or 'tiers' is required."""
|
|
|
|
tiers: Optional[List[CreatePlanTierRequest]] = None
|
|
r"""Tiered pricing. Either 'amount' or 'tiers' is required."""
|
|
|
|
tier_behavior: Optional[CreatePlanTierBehaviorRequest] = None
|
|
|
|
interval_count: Optional[float] = 1
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
billing_units: Optional[float] = 1
|
|
r"""Units per price increment. Usage is rounded UP when billed (e.g. billing_units=100 means 101 rounds to 200)."""
|
|
|
|
max_purchase: Optional[float] = None
|
|
r"""Max units purchasable beyond included. E.g. included=100, max_purchase=300 allows 400 total."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(
|
|
[
|
|
"amount",
|
|
"tiers",
|
|
"tier_behavior",
|
|
"interval_count",
|
|
"billing_units",
|
|
"max_purchase",
|
|
]
|
|
)
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanOnIncrease = Literal[
|
|
"bill_immediately",
|
|
"prorate_immediately",
|
|
"prorate_next_cycle",
|
|
"bill_next_cycle",
|
|
]
|
|
r"""Billing behavior when quantity increases mid-cycle."""
|
|
|
|
|
|
CreatePlanOnDecrease = Literal[
|
|
"prorate",
|
|
"prorate_immediately",
|
|
"prorate_next_cycle",
|
|
"none",
|
|
"no_prorations",
|
|
]
|
|
r"""Credit behavior when quantity decreases mid-cycle."""
|
|
|
|
|
|
class CreatePlanProrationTypedDict(TypedDict):
|
|
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
|
|
|
|
on_increase: CreatePlanOnIncrease
|
|
r"""Billing behavior when quantity increases mid-cycle."""
|
|
on_decrease: CreatePlanOnDecrease
|
|
r"""Credit behavior when quantity decreases mid-cycle."""
|
|
|
|
|
|
class CreatePlanProration(BaseModel):
|
|
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
|
|
|
|
on_increase: CreatePlanOnIncrease
|
|
r"""Billing behavior when quantity increases mid-cycle."""
|
|
|
|
on_decrease: CreatePlanOnDecrease
|
|
r"""Credit behavior when quantity decreases mid-cycle."""
|
|
|
|
|
|
CreatePlanExpiryDurationTypeRequest = Literal[
|
|
"month",
|
|
"forever",
|
|
]
|
|
r"""When rolled over units expire."""
|
|
|
|
|
|
class CreatePlanRolloverRequestTypedDict(TypedDict):
|
|
r"""Rollover config for unused units. If set, unused included units carry over."""
|
|
|
|
expiry_duration_type: CreatePlanExpiryDurationTypeRequest
|
|
r"""When rolled over units expire."""
|
|
max: NotRequired[float]
|
|
r"""Max rollover units. Omit for unlimited rollover."""
|
|
expiry_duration_length: NotRequired[float]
|
|
r"""Number of periods before expiry."""
|
|
|
|
|
|
class CreatePlanRolloverRequest(BaseModel):
|
|
r"""Rollover config for unused units. If set, unused included units carry over."""
|
|
|
|
expiry_duration_type: CreatePlanExpiryDurationTypeRequest
|
|
r"""When rolled over units expire."""
|
|
|
|
max: Optional[float] = None
|
|
r"""Max rollover units. Omit for unlimited rollover."""
|
|
|
|
expiry_duration_length: Optional[float] = None
|
|
r"""Number of periods before expiry."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["max", "expiry_duration_length"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanPlanItemTypedDict(TypedDict):
|
|
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
|
|
|
|
feature_id: str
|
|
r"""The ID of the feature to configure."""
|
|
included: NotRequired[float]
|
|
r"""Number of free units included. Balance resets to this each interval for consumable features."""
|
|
unlimited: NotRequired[bool]
|
|
r"""If true, customer has unlimited access to this feature."""
|
|
reset: NotRequired[CreatePlanResetRequestTypedDict]
|
|
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
|
|
price: NotRequired[CreatePlanItemPriceRequestTypedDict]
|
|
r"""Pricing for usage beyond included units. Omit for free features."""
|
|
proration: NotRequired[CreatePlanProrationTypedDict]
|
|
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
|
|
rollover: NotRequired[CreatePlanRolloverRequestTypedDict]
|
|
r"""Rollover config for unused units. If set, unused included units carry over."""
|
|
|
|
|
|
class CreatePlanPlanItem(BaseModel):
|
|
r"""Configuration for a feature item in a plan, including usage limits, pricing, and rollover settings."""
|
|
|
|
feature_id: str
|
|
r"""The ID of the feature to configure."""
|
|
|
|
included: Optional[float] = None
|
|
r"""Number of free units included. Balance resets to this each interval for consumable features."""
|
|
|
|
unlimited: Optional[bool] = None
|
|
r"""If true, customer has unlimited access to this feature."""
|
|
|
|
reset: Optional[CreatePlanResetRequest] = None
|
|
r"""Reset configuration for consumable features. Omit for non-consumable features like seats."""
|
|
|
|
price: Optional[CreatePlanItemPriceRequest] = None
|
|
r"""Pricing for usage beyond included units. Omit for free features."""
|
|
|
|
proration: Optional[CreatePlanProration] = None
|
|
r"""Proration settings for prepaid features. Controls mid-cycle quantity change billing."""
|
|
|
|
rollover: Optional[CreatePlanRolloverRequest] = None
|
|
r"""Rollover config for unused units. If set, unused included units carry over."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(
|
|
["included", "unlimited", "reset", "price", "proration", "rollover"]
|
|
)
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanDurationTypeRequest = Literal[
|
|
"day",
|
|
"month",
|
|
"year",
|
|
]
|
|
r"""Unit of time for the trial ('day', 'month', 'year')."""
|
|
|
|
|
|
class FreeTrialRequestTypedDict(TypedDict):
|
|
r"""Free trial configuration. Customers can try this plan before being charged."""
|
|
|
|
duration_length: float
|
|
r"""Number of duration_type periods the trial lasts."""
|
|
duration_type: NotRequired[CreatePlanDurationTypeRequest]
|
|
r"""Unit of time for the trial ('day', 'month', 'year')."""
|
|
card_required: NotRequired[bool]
|
|
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
|
|
|
|
|
|
class FreeTrialRequest(BaseModel):
|
|
r"""Free trial configuration. Customers can try this plan before being charged."""
|
|
|
|
duration_length: float
|
|
r"""Number of duration_type periods the trial lasts."""
|
|
|
|
duration_type: Optional[CreatePlanDurationTypeRequest] = "month"
|
|
r"""Unit of time for the trial ('day', 'month', 'year')."""
|
|
|
|
card_required: Optional[bool] = True
|
|
r"""If true, payment method required to start trial. Customer is charged after trial ends."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["duration_type", "card_required"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanParamsTypedDict(TypedDict):
|
|
plan_id: str
|
|
r"""The ID of the plan to create."""
|
|
name: str
|
|
r"""Display name of the plan."""
|
|
group: NotRequired[str]
|
|
r"""Group identifier for organizing related plans. Plans in the same group are mutually exclusive."""
|
|
description: NotRequired[Nullable[str]]
|
|
r"""Optional description of the plan."""
|
|
add_on: NotRequired[bool]
|
|
r"""If true, this plan can be attached alongside other plans. Otherwise, attaching replaces existing plans in the same group."""
|
|
auto_enable: NotRequired[bool]
|
|
r"""If true, plan is automatically attached when a customer is created. Use for free tiers."""
|
|
price: NotRequired[CreatePlanPriceRequestTypedDict]
|
|
r"""Base recurring price for the plan. Omit for free or usage-only plans."""
|
|
items: NotRequired[List[CreatePlanPlanItemTypedDict]]
|
|
r"""Feature configurations for this plan. Each item defines included units, pricing, and reset behavior."""
|
|
free_trial: NotRequired[FreeTrialRequestTypedDict]
|
|
r"""Free trial configuration. Customers can try this plan before being charged."""
|
|
|
|
|
|
class CreatePlanParams(BaseModel):
|
|
plan_id: str
|
|
r"""The ID of the plan to create."""
|
|
|
|
name: str
|
|
r"""Display name of the plan."""
|
|
|
|
group: Optional[str] = ""
|
|
r"""Group identifier for organizing related plans. Plans in the same group are mutually exclusive."""
|
|
|
|
description: OptionalNullable[str] = UNSET
|
|
r"""Optional description of the plan."""
|
|
|
|
add_on: Optional[bool] = False
|
|
r"""If true, this plan can be attached alongside other plans. Otherwise, attaching replaces existing plans in the same group."""
|
|
|
|
auto_enable: Optional[bool] = False
|
|
r"""If true, plan is automatically attached when a customer is created. Use for free tiers."""
|
|
|
|
price: Optional[CreatePlanPriceRequest] = None
|
|
r"""Base recurring price for the plan. Omit for free or usage-only plans."""
|
|
|
|
items: Optional[List[CreatePlanPlanItem]] = None
|
|
r"""Feature configurations for this plan. Each item defines included units, pricing, and reset behavior."""
|
|
|
|
free_trial: Optional[FreeTrialRequest] = None
|
|
r"""Free trial configuration. Customers can try this plan before being charged."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(
|
|
[
|
|
"group",
|
|
"description",
|
|
"add_on",
|
|
"auto_enable",
|
|
"price",
|
|
"items",
|
|
"free_trial",
|
|
]
|
|
)
|
|
nullable_fields = set(["description"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanPriceIntervalResponse = Union[
|
|
Literal[
|
|
"one_off",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
|
|
|
|
class CreatePlanPriceDisplayTypedDict(TypedDict):
|
|
r"""Display text for showing this price in pricing pages."""
|
|
|
|
primary_text: str
|
|
r"""Main display text (e.g. '$10' or '100 messages')."""
|
|
secondary_text: NotRequired[str]
|
|
r"""Secondary display text (e.g. 'per month' or 'then $0.5 per 100')."""
|
|
|
|
|
|
class CreatePlanPriceDisplay(BaseModel):
|
|
r"""Display text for showing this price in pricing pages."""
|
|
|
|
primary_text: str
|
|
r"""Main display text (e.g. '$10' or '100 messages')."""
|
|
|
|
secondary_text: Optional[str] = None
|
|
r"""Secondary display text (e.g. 'per month' or 'then $0.5 per 100')."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["secondary_text"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanPriceResponseTypedDict(TypedDict):
|
|
amount: float
|
|
r"""Base price amount for the plan."""
|
|
interval: CreatePlanPriceIntervalResponse
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
display: NotRequired[CreatePlanPriceDisplayTypedDict]
|
|
r"""Display text for showing this price in pricing pages."""
|
|
|
|
|
|
class CreatePlanPriceResponse(BaseModel):
|
|
amount: float
|
|
r"""Base price amount for the plan."""
|
|
|
|
interval: CreatePlanPriceIntervalResponse
|
|
r"""Billing interval (e.g. 'month', 'year')."""
|
|
|
|
interval_count: Optional[float] = None
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
display: Optional[CreatePlanPriceDisplay] = None
|
|
r"""Display text for showing this price in pricing pages."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["interval_count", "display"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanType = Union[
|
|
Literal[
|
|
"static",
|
|
"boolean",
|
|
"single_use",
|
|
"continuous_use",
|
|
"credit_system",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""The type of the feature"""
|
|
|
|
|
|
class CreatePlanFeatureDisplayTypedDict(TypedDict):
|
|
singular: str
|
|
r"""The singular display name for the feature."""
|
|
plural: str
|
|
r"""The plural display name for the feature."""
|
|
|
|
|
|
class CreatePlanFeatureDisplay(BaseModel):
|
|
singular: str
|
|
r"""The singular display name for the feature."""
|
|
|
|
plural: str
|
|
r"""The plural display name for the feature."""
|
|
|
|
|
|
class CreatePlanCreditSchemaTypedDict(TypedDict):
|
|
metered_feature_id: str
|
|
r"""The ID of the metered feature (should be a single_use feature)."""
|
|
credit_cost: float
|
|
r"""The credit cost of the metered feature."""
|
|
|
|
|
|
class CreatePlanCreditSchema(BaseModel):
|
|
metered_feature_id: str
|
|
r"""The ID of the metered feature (should be a single_use feature)."""
|
|
|
|
credit_cost: float
|
|
r"""The credit cost of the metered feature."""
|
|
|
|
|
|
class CreatePlanFeatureTypedDict(TypedDict):
|
|
r"""The full feature object if expanded."""
|
|
|
|
id: str
|
|
r"""The ID of the feature, used to refer to it in other API calls like /track or /check."""
|
|
type: CreatePlanType
|
|
r"""The type of the feature"""
|
|
name: NotRequired[Nullable[str]]
|
|
r"""The name of the feature."""
|
|
display: NotRequired[Nullable[CreatePlanFeatureDisplayTypedDict]]
|
|
r"""Singular and plural display names for the feature."""
|
|
credit_schema: NotRequired[Nullable[List[CreatePlanCreditSchemaTypedDict]]]
|
|
r"""Credit cost schema for credit system features."""
|
|
archived: NotRequired[Nullable[bool]]
|
|
r"""Whether or not the feature is archived."""
|
|
|
|
|
|
class CreatePlanFeature(BaseModel):
|
|
r"""The full feature object if expanded."""
|
|
|
|
id: str
|
|
r"""The ID of the feature, used to refer to it in other API calls like /track or /check."""
|
|
|
|
type: CreatePlanType
|
|
r"""The type of the feature"""
|
|
|
|
name: OptionalNullable[str] = UNSET
|
|
r"""The name of the feature."""
|
|
|
|
display: OptionalNullable[CreatePlanFeatureDisplay] = UNSET
|
|
r"""Singular and plural display names for the feature."""
|
|
|
|
credit_schema: OptionalNullable[List[CreatePlanCreditSchema]] = UNSET
|
|
r"""Credit cost schema for credit system features."""
|
|
|
|
archived: OptionalNullable[bool] = UNSET
|
|
r"""Whether or not the feature is archived."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["name", "display", "credit_schema", "archived"])
|
|
nullable_fields = set(["name", "display", "credit_schema", "archived"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanResetIntervalResponse = Union[
|
|
Literal[
|
|
"one_off",
|
|
"minute",
|
|
"hour",
|
|
"day",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""The interval at which the feature balance resets (e.g. 'month', 'year'). For consumable features, usage resets to 0 and included units are restored."""
|
|
|
|
|
|
class CreatePlanResetResponseTypedDict(TypedDict):
|
|
interval: CreatePlanResetIntervalResponse
|
|
r"""The interval at which the feature balance resets (e.g. 'month', 'year'). For consumable features, usage resets to 0 and included units are restored."""
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals between resets. Defaults to 1."""
|
|
|
|
|
|
class CreatePlanResetResponse(BaseModel):
|
|
interval: CreatePlanResetIntervalResponse
|
|
r"""The interval at which the feature balance resets (e.g. 'month', 'year'). For consumable features, usage resets to 0 and included units are restored."""
|
|
|
|
interval_count: Optional[float] = None
|
|
r"""Number of intervals between resets. Defaults to 1."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["interval_count"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanToResponseTypedDict = TypeAliasType(
|
|
"CreatePlanToResponseTypedDict", Union[float, str]
|
|
)
|
|
|
|
|
|
CreatePlanToResponse = TypeAliasType("CreatePlanToResponse", Union[float, str])
|
|
|
|
|
|
class CreatePlanTierResponseTypedDict(TypedDict):
|
|
to: CreatePlanToResponseTypedDict
|
|
amount: float
|
|
flat_amount: NotRequired[Nullable[float]]
|
|
|
|
|
|
class CreatePlanTierResponse(BaseModel):
|
|
to: CreatePlanToResponse
|
|
|
|
amount: float
|
|
|
|
flat_amount: OptionalNullable[float] = UNSET
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["flat_amount"])
|
|
nullable_fields = set(["flat_amount"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanTierBehaviorResponse = Union[
|
|
Literal[
|
|
"graduated",
|
|
"volume",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
|
|
|
|
CreatePlanPriceItemIntervalResponse = Union[
|
|
Literal[
|
|
"one_off",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"semi_annual",
|
|
"year",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""Billing interval for this price. For consumable features, should match reset.interval."""
|
|
|
|
|
|
CreatePlanBillingMethodResponse = Union[
|
|
Literal[
|
|
"prepaid",
|
|
"usage_based",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""'prepaid' for features like seats where customers pay upfront, 'usage_based' for pay-as-you-go after included usage."""
|
|
|
|
|
|
class CreatePlanItemPriceResponseTypedDict(TypedDict):
|
|
interval: CreatePlanPriceItemIntervalResponse
|
|
r"""Billing interval for this price. For consumable features, should match reset.interval."""
|
|
billing_units: float
|
|
r"""Number of units per price increment. Usage is rounded UP to the nearest billing_units when billed (e.g. billing_units=100 means 101 usage rounds to 200)."""
|
|
billing_method: CreatePlanBillingMethodResponse
|
|
r"""'prepaid' for features like seats where customers pay upfront, 'usage_based' for pay-as-you-go after included usage."""
|
|
max_purchase: Nullable[float]
|
|
r"""Maximum units a customer can purchase beyond included. E.g. if included=100 and max_purchase=300, customer can use up to 400 total before usage is capped. Null for no limit."""
|
|
amount: NotRequired[float]
|
|
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
|
|
tiers: NotRequired[List[CreatePlanTierResponseTypedDict]]
|
|
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
|
|
tier_behavior: NotRequired[CreatePlanTierBehaviorResponse]
|
|
interval_count: NotRequired[float]
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
|
|
class CreatePlanItemPriceResponse(BaseModel):
|
|
interval: CreatePlanPriceItemIntervalResponse
|
|
r"""Billing interval for this price. For consumable features, should match reset.interval."""
|
|
|
|
billing_units: float
|
|
r"""Number of units per price increment. Usage is rounded UP to the nearest billing_units when billed (e.g. billing_units=100 means 101 usage rounds to 200)."""
|
|
|
|
billing_method: CreatePlanBillingMethodResponse
|
|
r"""'prepaid' for features like seats where customers pay upfront, 'usage_based' for pay-as-you-go after included usage."""
|
|
|
|
max_purchase: Nullable[float]
|
|
r"""Maximum units a customer can purchase beyond included. E.g. if included=100 and max_purchase=300, customer can use up to 400 total before usage is capped. Null for no limit."""
|
|
|
|
amount: Optional[float] = None
|
|
r"""Price per billing_units after included usage is consumed. Mutually exclusive with tiers."""
|
|
|
|
tiers: Optional[List[CreatePlanTierResponse]] = None
|
|
r"""Tiered pricing configuration. Each tier's 'to' INCLUDES the included amount. Either 'tiers' or 'amount' is required."""
|
|
|
|
tier_behavior: Optional[CreatePlanTierBehaviorResponse] = None
|
|
|
|
interval_count: Optional[float] = None
|
|
r"""Number of intervals per billing cycle. Defaults to 1."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["amount", "tiers", "tier_behavior", "interval_count"])
|
|
nullable_fields = set(["max_purchase"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanItemDisplayTypedDict(TypedDict):
|
|
r"""Display text for showing this item in pricing pages."""
|
|
|
|
primary_text: str
|
|
r"""Main display text (e.g. '$10' or '100 messages')."""
|
|
secondary_text: NotRequired[str]
|
|
r"""Secondary display text (e.g. 'per month' or 'then $0.5 per 100')."""
|
|
|
|
|
|
class CreatePlanItemDisplay(BaseModel):
|
|
r"""Display text for showing this item in pricing pages."""
|
|
|
|
primary_text: str
|
|
r"""Main display text (e.g. '$10' or '100 messages')."""
|
|
|
|
secondary_text: Optional[str] = None
|
|
r"""Secondary display text (e.g. 'per month' or 'then $0.5 per 100')."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["secondary_text"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanExpiryDurationTypeResponse = Union[
|
|
Literal[
|
|
"month",
|
|
"forever",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""When rolled over units expire."""
|
|
|
|
|
|
class CreatePlanRolloverResponseTypedDict(TypedDict):
|
|
r"""Rollover configuration for unused units. If set, unused included units roll over to the next period."""
|
|
|
|
max: Nullable[float]
|
|
r"""Maximum rollover units. Null for unlimited rollover."""
|
|
expiry_duration_type: CreatePlanExpiryDurationTypeResponse
|
|
r"""When rolled over units expire."""
|
|
expiry_duration_length: NotRequired[float]
|
|
r"""Number of periods before expiry."""
|
|
|
|
|
|
class CreatePlanRolloverResponse(BaseModel):
|
|
r"""Rollover configuration for unused units. If set, unused included units roll over to the next period."""
|
|
|
|
max: Nullable[float]
|
|
r"""Maximum rollover units. Null for unlimited rollover."""
|
|
|
|
expiry_duration_type: CreatePlanExpiryDurationTypeResponse
|
|
r"""When rolled over units expire."""
|
|
|
|
expiry_duration_length: Optional[float] = None
|
|
r"""Number of periods before expiry."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["expiry_duration_length"])
|
|
nullable_fields = set(["max"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanItemTypedDict(TypedDict):
|
|
feature_id: str
|
|
r"""The ID of the feature this item configures."""
|
|
included: float
|
|
r"""Number of free units included. For consumable features, balance resets to this number each interval."""
|
|
unlimited: bool
|
|
r"""Whether the customer has unlimited access to this feature."""
|
|
reset: Nullable[CreatePlanResetResponseTypedDict]
|
|
r"""Reset configuration for consumable features. Null for non-consumable features like seats where usage persists across billing cycles."""
|
|
price: Nullable[CreatePlanItemPriceResponseTypedDict]
|
|
r"""Pricing configuration for usage beyond included units. Null if feature is entirely free."""
|
|
feature: NotRequired[CreatePlanFeatureTypedDict]
|
|
r"""The full feature object if expanded."""
|
|
display: NotRequired[CreatePlanItemDisplayTypedDict]
|
|
r"""Display text for showing this item in pricing pages."""
|
|
rollover: NotRequired[CreatePlanRolloverResponseTypedDict]
|
|
r"""Rollover configuration for unused units. If set, unused included units roll over to the next period."""
|
|
|
|
|
|
class CreatePlanItem(BaseModel):
|
|
feature_id: str
|
|
r"""The ID of the feature this item configures."""
|
|
|
|
included: float
|
|
r"""Number of free units included. For consumable features, balance resets to this number each interval."""
|
|
|
|
unlimited: bool
|
|
r"""Whether the customer has unlimited access to this feature."""
|
|
|
|
reset: Nullable[CreatePlanResetResponse]
|
|
r"""Reset configuration for consumable features. Null for non-consumable features like seats where usage persists across billing cycles."""
|
|
|
|
price: Nullable[CreatePlanItemPriceResponse]
|
|
r"""Pricing configuration for usage beyond included units. Null if feature is entirely free."""
|
|
|
|
feature: Optional[CreatePlanFeature] = None
|
|
r"""The full feature object if expanded."""
|
|
|
|
display: Optional[CreatePlanItemDisplay] = None
|
|
r"""Display text for showing this item in pricing pages."""
|
|
|
|
rollover: Optional[CreatePlanRolloverResponse] = None
|
|
r"""Rollover configuration for unused units. If set, unused included units roll over to the next period."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["feature", "display", "rollover"])
|
|
nullable_fields = set(["reset", "price"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
CreatePlanDurationTypeResponse = Union[
|
|
Literal[
|
|
"day",
|
|
"month",
|
|
"year",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""Unit of time for the trial duration ('day', 'month', 'year')."""
|
|
|
|
|
|
class CreatePlanFreeTrialResponseTypedDict(TypedDict):
|
|
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
|
|
|
duration_length: float
|
|
r"""Number of duration_type periods the trial lasts."""
|
|
duration_type: CreatePlanDurationTypeResponse
|
|
r"""Unit of time for the trial duration ('day', 'month', 'year')."""
|
|
card_required: bool
|
|
r"""Whether a payment method is required to start the trial. If true, customer will be charged after trial ends."""
|
|
|
|
|
|
class CreatePlanFreeTrialResponse(BaseModel):
|
|
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
|
|
|
duration_length: float
|
|
r"""Number of duration_type periods the trial lasts."""
|
|
|
|
duration_type: CreatePlanDurationTypeResponse
|
|
r"""Unit of time for the trial duration ('day', 'month', 'year')."""
|
|
|
|
card_required: bool
|
|
r"""Whether a payment method is required to start the trial. If true, customer will be charged after trial ends."""
|
|
|
|
|
|
CreatePlanEnv = Union[
|
|
Literal[
|
|
"sandbox",
|
|
"live",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
|
|
|
|
|
CreatePlanScenario = Union[
|
|
Literal[
|
|
"scheduled",
|
|
"active",
|
|
"new",
|
|
"renew",
|
|
"upgrade",
|
|
"downgrade",
|
|
"cancel",
|
|
"expired",
|
|
"past_due",
|
|
],
|
|
UnrecognizedStr,
|
|
]
|
|
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
|
|
|
|
|
|
class CreatePlanCustomerEligibilityTypedDict(TypedDict):
|
|
scenario: CreatePlanScenario
|
|
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
|
|
trial_available: NotRequired[bool]
|
|
r"""Whether a free trial is available for this customer."""
|
|
|
|
|
|
class CreatePlanCustomerEligibility(BaseModel):
|
|
scenario: CreatePlanScenario
|
|
r"""The attach scenario for this customer (e.g. new_subscription, upgrade, downgrade)."""
|
|
|
|
trial_available: Optional[bool] = None
|
|
r"""Whether a free trial is available for this customer."""
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["trial_available"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if val is not None or k not in optional_fields:
|
|
m[k] = val
|
|
|
|
return m
|
|
|
|
|
|
class CreatePlanResponseTypedDict(TypedDict):
|
|
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
|
|
|
|
id: str
|
|
r"""Unique identifier for the plan."""
|
|
name: str
|
|
r"""Display name of the plan."""
|
|
description: Nullable[str]
|
|
r"""Optional description of the plan."""
|
|
group: Nullable[str]
|
|
r"""Group identifier for organizing related plans. Plans in the same group are mutually exclusive."""
|
|
version: float
|
|
r"""Version number of the plan. Incremented when plan configuration changes."""
|
|
add_on: bool
|
|
r"""Whether this is an add-on plan that can be attached alongside a main plan."""
|
|
auto_enable: bool
|
|
r"""If true, this plan is automatically attached when a customer is created. Used for free plans."""
|
|
price: Nullable[CreatePlanPriceResponseTypedDict]
|
|
r"""Base recurring price for the plan. Null for free plans or usage-only plans."""
|
|
items: List[CreatePlanItemTypedDict]
|
|
r"""Feature configurations included in this plan. Each item defines included units, pricing, and reset behavior for a feature."""
|
|
created_at: float
|
|
r"""Unix timestamp (ms) when the plan was created."""
|
|
env: CreatePlanEnv
|
|
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
|
archived: bool
|
|
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
|
base_variant_id: Nullable[str]
|
|
r"""If this is a variant, the ID of the base plan it was created from."""
|
|
free_trial: NotRequired[CreatePlanFreeTrialResponseTypedDict]
|
|
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
|
customer_eligibility: NotRequired[CreatePlanCustomerEligibilityTypedDict]
|
|
|
|
|
|
class CreatePlanResponse(BaseModel):
|
|
r"""A plan defines a set of features, pricing, and entitlements that can be attached to customers."""
|
|
|
|
id: str
|
|
r"""Unique identifier for the plan."""
|
|
|
|
name: str
|
|
r"""Display name of the plan."""
|
|
|
|
description: Nullable[str]
|
|
r"""Optional description of the plan."""
|
|
|
|
group: Nullable[str]
|
|
r"""Group identifier for organizing related plans. Plans in the same group are mutually exclusive."""
|
|
|
|
version: float
|
|
r"""Version number of the plan. Incremented when plan configuration changes."""
|
|
|
|
add_on: bool
|
|
r"""Whether this is an add-on plan that can be attached alongside a main plan."""
|
|
|
|
auto_enable: bool
|
|
r"""If true, this plan is automatically attached when a customer is created. Used for free plans."""
|
|
|
|
price: Nullable[CreatePlanPriceResponse]
|
|
r"""Base recurring price for the plan. Null for free plans or usage-only plans."""
|
|
|
|
items: List[CreatePlanItem]
|
|
r"""Feature configurations included in this plan. Each item defines included units, pricing, and reset behavior for a feature."""
|
|
|
|
created_at: float
|
|
r"""Unix timestamp (ms) when the plan was created."""
|
|
|
|
env: CreatePlanEnv
|
|
r"""Environment this plan belongs to ('sandbox' or 'live')."""
|
|
|
|
archived: bool
|
|
r"""Whether the plan is archived. Archived plans cannot be attached to new customers."""
|
|
|
|
base_variant_id: Nullable[str]
|
|
r"""If this is a variant, the ID of the base plan it was created from."""
|
|
|
|
free_trial: Optional[CreatePlanFreeTrialResponse] = None
|
|
r"""Free trial configuration. If set, new customers can try this plan before being charged."""
|
|
|
|
customer_eligibility: Optional[CreatePlanCustomerEligibility] = None
|
|
|
|
@model_serializer(mode="wrap")
|
|
def serialize_model(self, handler):
|
|
optional_fields = set(["free_trial", "customer_eligibility"])
|
|
nullable_fields = set(["description", "group", "price", "base_variant_id"])
|
|
serialized = handler(self)
|
|
m = {}
|
|
|
|
for n, f in type(self).model_fields.items():
|
|
k = f.alias or n
|
|
val = serialized.get(k)
|
|
is_nullable_and_explicitly_set = (
|
|
k in nullable_fields
|
|
and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
|
|
)
|
|
|
|
if val != UNSET_SENTINEL:
|
|
if (
|
|
val is not None
|
|
or k not in optional_fields
|
|
or is_nullable_and_explicitly_set
|
|
):
|
|
m[k] = val
|
|
|
|
return m
|