diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b2585653..9a61761c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.16.0" -} \ No newline at end of file + ".": "2.17.0" +} diff --git a/.stats.yml b/.stats.yml index e670c774..bca80a58 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 97 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-bf3e71b33372f4a9307f4b6cb689ea46b3cf583ecc5d79eee9601cd0b0467c9a.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-e9785c0b77f4a91dd668d12d707abdaa63cc527029c9d62a92ac24ec40500d18.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0efd74be..acb6b6d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## 2.17.0 (2024-11-28) + +Full Changelog: [v2.16.0...v2.17.0](https://github.com/orbcorp/orb-python/compare/v2.16.0...v2.17.0) + +### Features + +* api updates ([3dc9d02](https://github.com/orbcorp/orb-python/commit/3dc9d0223a4ed8eb8e76a2688e4e7d78cf1700a9)) +* **api:** api update ([#436](https://github.com/orbcorp/orb-python/issues/436)) ([6f8c441](https://github.com/orbcorp/orb-python/commit/6f8c441a369dacf871344a5ab8b5d654011447fb)) +* **api:** api update ([#440](https://github.com/orbcorp/orb-python/issues/440)) ([790b52a](https://github.com/orbcorp/orb-python/commit/790b52ac9898f55de3faf17ac3a27213f22bc711)) +* **api:** api update ([#441](https://github.com/orbcorp/orb-python/issues/441)) ([e0268df](https://github.com/orbcorp/orb-python/commit/e0268dfe3a2f73acff5d1f7a6fcfea43a90ce3f0)) +* **api:** api update ([#443](https://github.com/orbcorp/orb-python/issues/443)) ([285ba54](https://github.com/orbcorp/orb-python/commit/285ba54b140de61f24fab688c9c69ab80166ebed)) + + +### Bug Fixes + +* **client:** compat with new httpx 0.28.0 release ([#444](https://github.com/orbcorp/orb-python/issues/444)) ([e0f2966](https://github.com/orbcorp/orb-python/commit/e0f2966dfe55a98fc77285ea348a8872b5c09921)) + + +### Chores + +* fix formatting ([f3da812](https://github.com/orbcorp/orb-python/commit/f3da812e90ad9ea9d5ba881bfd322d8ede076708)) +* **internal:** codegen related update ([#442](https://github.com/orbcorp/orb-python/issues/442)) ([f3efb3f](https://github.com/orbcorp/orb-python/commit/f3efb3fe137f751871ad97606d9c624ba5b5774e)) +* **internal:** fix compat model_dump method when warnings are passed ([#437](https://github.com/orbcorp/orb-python/issues/437)) ([e03dc3b](https://github.com/orbcorp/orb-python/commit/e03dc3b864150b1a3de24952aa7a503e5dba7254)) +* remove now unused `cached-property` dep ([#439](https://github.com/orbcorp/orb-python/issues/439)) ([e5e8485](https://github.com/orbcorp/orb-python/commit/e5e848510b6df79a3b1e61f5479a7241fcd18af6)) + + +### Documentation + +* add info log level to readme ([#438](https://github.com/orbcorp/orb-python/issues/438)) ([4576720](https://github.com/orbcorp/orb-python/commit/457672037ec56a9432800fec56c6deb68964b1df)) + ## 2.16.0 (2024-11-15) Full Changelog: [v2.15.0...v2.16.0](https://github.com/orbcorp/orb-python/compare/v2.15.0...v2.16.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab5143d3..abbbea65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,13 @@ ### With Rye -We use [Rye](https://rye.astral.sh/) to manage dependencies so we highly recommend [installing it](https://rye.astral.sh/guide/installation/) as it will automatically provision a Python environment with the expected Python version. +We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: -After installing Rye, you'll just have to run this command: +```sh +$ ./scripts/bootstrap +``` + +Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: ```sh $ rye sync --all-features @@ -31,25 +35,25 @@ $ pip install -r requirements-dev.lock ## Modifying/Adding code -Most of the SDK is generated code, and any modified code will be overridden on the next generation. The -`src/orb/lib/` and `examples/` directories are exceptions and will never be overridden. +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/orb/lib/` and `examples/` directories. ## Adding and running examples -All files in the `examples/` directory are not modified by the Stainless generator and can be freely edited or -added to. +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. -```bash +```py # add an example to examples/.py #!/usr/bin/env -S rye run python … ``` -``` -chmod +x examples/.py +```sh +$ chmod +x examples/.py # run the example against your api -./examples/.py +$ ./examples/.py ``` ## Using the repository from source @@ -58,8 +62,8 @@ If you’d like to use the repository from source, you can either install from g To install via git: -```bash -pip install git+ssh://git@github.com/orbcorp/orb-python.git +```sh +$ pip install git+ssh://git@github.com/orbcorp/orb-python.git ``` Alternatively, you can build from source and install the wheel file: @@ -68,29 +72,29 @@ Building this package will create two files in the `dist/` directory, a `.tar.gz To create a distributable version of the library, all you have to do is run this command: -```bash -rye build +```sh +$ rye build # or -python -m build +$ python -m build ``` Then to install: ```sh -pip install ./path-to-wheel-file.whl +$ pip install ./path-to-wheel-file.whl ``` ## Running tests Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. -```bash +```sh # you will need npm installed -npx prism mock path/to/your/openapi.yml +$ npx prism mock path/to/your/openapi.yml ``` -```bash -rye run pytest +```sh +$ ./scripts/test ``` ## Linting and formatting @@ -100,14 +104,14 @@ This repository uses [ruff](https://github.com/astral-sh/ruff) and To lint: -```bash -rye run lint +```sh +$ ./scripts/lint ``` To format and fix all ruff issues automatically: -```bash -rye run format +```sh +$ ./scripts/format ``` ## Publishing and releases diff --git a/README.md b/README.md index 1bc81f80..0870cd51 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![PyPI version](https://img.shields.io/pypi/v/orb-billing.svg)](https://pypi.org/project/orb-billing/) -The Orb Python library provides convenient access to the Orb REST API from any Python 3.7+ +The Orb Python library provides convenient access to the Orb REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -290,12 +290,14 @@ Note that requests that time out are [retried twice by default](#retries). We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. -You can enable logging by setting the environment variable `ORB_LOG` to `debug`. +You can enable logging by setting the environment variable `ORB_LOG` to `info`. ```shell -$ export ORB_LOG=debug +$ export ORB_LOG=info ``` +Or to `debug` for more verbose logging. + ### How to tell whether `None` means `null` or missing In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: @@ -434,6 +436,21 @@ We take backwards-compatibility seriously and work hard to ensure you can rely o We are keen for your feedback; please open an [issue](https://www.github.com/orbcorp/orb-python/issues) with questions, bugs, or suggestions. +### Determining the installed version + +If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. + +You can determine the version that is being used at runtime with: + +```py +import orb +print(orb.__version__) +``` + ## Requirements -Python 3.7 or higher. +Python 3.8 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/api.md b/api.md index 7d1e5f7a..a387852d 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,15 @@ # Shared Types ```python -from orb.types import BillingCycleRelativeDate, Discount, PaginationMetadata +from orb.types import ( + AmountDiscount, + BillingCycleRelativeDate, + Discount, + InvoiceLevelDiscount, + PaginationMetadata, + PercentageDiscount, + TrialDiscount, +) ``` # TopLevel @@ -47,6 +55,7 @@ from orb.types import CreditNote Methods: +- client.credit_notes.create(\*\*params) -> CreditNote - client.credit_notes.list(\*\*params) -> SyncPage[CreditNote] - client.credit_notes.fetch(credit_note_id) -> CreditNote @@ -191,6 +200,18 @@ Methods: - client.events.backfills.fetch(backfill_id) -> BackfillFetchResponse - client.events.backfills.revert(backfill_id) -> BackfillRevertResponse +## Volume + +Types: + +```python +from orb.types.events import EventVolumes +``` + +Methods: + +- client.events.volume.list(\*\*params) -> EventVolumes + # InvoiceLineItems Types: @@ -218,7 +239,7 @@ Methods: - client.invoices.list(\*\*params) -> SyncPage[Invoice] - client.invoices.fetch(invoice_id) -> Invoice - client.invoices.fetch_upcoming(\*\*params) -> InvoiceFetchUpcomingResponse -- client.invoices.issue(invoice_id) -> Invoice +- client.invoices.issue(invoice_id, \*\*params) -> Invoice - client.invoices.mark_paid(invoice_id, \*\*params) -> Invoice - client.invoices.pay(invoice_id) -> Invoice - client.invoices.void(invoice_id) -> Invoice @@ -307,28 +328,39 @@ from orb.types import ( Subscription, SubscriptionUsage, Subscriptions, + SubscriptionCreateResponse, + SubscriptionCancelResponse, SubscriptionFetchCostsResponse, SubscriptionFetchScheduleResponse, + SubscriptionPriceIntervalsResponse, + SubscriptionSchedulePlanChangeResponse, + SubscriptionTriggerPhaseResponse, + SubscriptionUnscheduleCancellationResponse, + SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, + SubscriptionUnschedulePendingPlanChangesResponse, + SubscriptionUpdateFixedFeeQuantityResponse, + SubscriptionUpdateTrialResponse, ) ``` Methods: -- client.subscriptions.create(\*\*params) -> Subscription +- client.subscriptions.create(\*\*params) -> SubscriptionCreateResponse - client.subscriptions.update(subscription_id, \*\*params) -> Subscription - client.subscriptions.list(\*\*params) -> SyncPage[Subscription] -- client.subscriptions.cancel(subscription_id, \*\*params) -> Subscription +- client.subscriptions.cancel(subscription_id, \*\*params) -> SubscriptionCancelResponse - client.subscriptions.fetch(subscription_id) -> Subscription - client.subscriptions.fetch_costs(subscription_id, \*\*params) -> SubscriptionFetchCostsResponse - client.subscriptions.fetch_schedule(subscription_id, \*\*params) -> SyncPage[SubscriptionFetchScheduleResponse] - client.subscriptions.fetch_usage(subscription_id, \*\*params) -> SubscriptionUsage -- client.subscriptions.price_intervals(subscription_id, \*\*params) -> Subscription -- client.subscriptions.schedule_plan_change(subscription_id, \*\*params) -> Subscription -- client.subscriptions.trigger_phase(subscription_id, \*\*params) -> Subscription -- client.subscriptions.unschedule_cancellation(subscription_id) -> Subscription -- client.subscriptions.unschedule_fixed_fee_quantity_updates(subscription_id, \*\*params) -> Subscription -- client.subscriptions.unschedule_pending_plan_changes(subscription_id) -> Subscription -- client.subscriptions.update_fixed_fee_quantity(subscription_id, \*\*params) -> Subscription +- client.subscriptions.price_intervals(subscription_id, \*\*params) -> SubscriptionPriceIntervalsResponse +- client.subscriptions.schedule_plan_change(subscription_id, \*\*params) -> SubscriptionSchedulePlanChangeResponse +- client.subscriptions.trigger_phase(subscription_id, \*\*params) -> SubscriptionTriggerPhaseResponse +- client.subscriptions.unschedule_cancellation(subscription_id) -> SubscriptionUnscheduleCancellationResponse +- client.subscriptions.unschedule_fixed_fee_quantity_updates(subscription_id, \*\*params) -> SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse +- client.subscriptions.unschedule_pending_plan_changes(subscription_id) -> SubscriptionUnschedulePendingPlanChangesResponse +- client.subscriptions.update_fixed_fee_quantity(subscription_id, \*\*params) -> SubscriptionUpdateFixedFeeQuantityResponse +- client.subscriptions.update_trial(subscription_id, \*\*params) -> SubscriptionUpdateTrialResponse # Webhooks diff --git a/mypy.ini b/mypy.ini index 283a4e20..4f22c5a2 100644 --- a/mypy.ini +++ b/mypy.ini @@ -5,7 +5,10 @@ show_error_codes = True # Exclude _files.py because mypy isn't smart enough to apply # the correct type narrowing and as this is an internal module # it's fine to just use Pyright. -exclude = ^(src/orb/_files\.py|_dev/.*\.py)$ +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ^(src/orb/_files\.py|_dev/.*\.py|tests/.*)$ strict_equality = True implicit_reexport = True diff --git a/pyproject.toml b/pyproject.toml index 43bff382..373c2520 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "orb-billing" -version = "2.16.0" +version = "2.17.0" description = "The official Python library for the orb API" dynamic = ["readme"] license = "Apache-2.0" @@ -14,13 +14,11 @@ dependencies = [ "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", - "cached-property; python_version < '3.8'", ] -requires-python = ">= 3.7" +requires-python = ">= 3.8" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -56,6 +54,7 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", + "nest_asyncio==1.6.0" ] [tool.rye.scripts] @@ -63,11 +62,11 @@ format = { chain = [ "format:ruff", "format:docs", "fix:ruff", + # run formatting again to fix any inconsistencies when imports are stripped + "format:ruff", ]} -"format:black" = "black ." "format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" "format:ruff" = "ruff format" -"format:isort" = "isort ." "lint" = { chain = [ "check:ruff", @@ -125,10 +124,6 @@ path = "README.md" pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' replacement = '[\1](https://github.com/orbcorp/orb-python/tree/main/\g<2>)' -[tool.black] -line-length = 120 -target-version = ["py37"] - [tool.pytest.ini_options] testpaths = ["tests"] addopts = "--tb=short" @@ -143,7 +138,7 @@ filterwarnings = [ # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.7" +pythonVersion = "3.8" exclude = [ "_dev", diff --git a/requirements-dev.lock b/requirements-dev.lock index 3eed038a..67107cde 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -16,8 +16,6 @@ anyio==4.4.0 # via orb-billing argcomplete==3.1.2 # via nox -attrs==23.1.0 - # via pytest certifi==2023.7.22 # via httpcore # via httpx @@ -28,8 +26,9 @@ distlib==0.3.7 # via virtualenv distro==1.8.0 # via orb-billing -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio + # via pytest filelock==3.12.4 # via virtualenv h11==0.14.0 @@ -49,9 +48,10 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -mypy==1.10.1 +mypy==1.13.0 mypy-extensions==1.0.0 # via mypy +nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 @@ -60,27 +60,25 @@ packaging==23.2 # via pytest platformdirs==3.11.0 # via virtualenv -pluggy==1.3.0 - # via pytest -py==1.11.0 +pluggy==1.5.0 # via pytest -pydantic==2.7.1 +pydantic==2.9.2 # via orb-billing -pydantic-core==2.18.2 +pydantic-core==2.23.4 # via pydantic pygments==2.18.0 # via rich -pyright==1.1.374 -pytest==7.1.1 +pyright==1.1.380 +pytest==8.3.3 # via pytest-asyncio -pytest-asyncio==0.21.1 +pytest-asyncio==0.24.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 # via dirty-equals respx==0.20.2 rich==13.7.1 -ruff==0.5.6 +ruff==0.6.9 setuptools==68.2.2 # via nodeenv six==1.16.0 @@ -90,10 +88,10 @@ sniffio==1.3.0 # via httpx # via orb-billing time-machine==2.9.0 -tomli==2.0.1 +tomli==2.0.2 # via mypy # via pytest -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via anyio # via mypy # via orb-billing diff --git a/requirements.lock b/requirements.lock index 45c1b68d..f452fd2d 100644 --- a/requirements.lock +++ b/requirements.lock @@ -19,7 +19,7 @@ certifi==2023.7.22 # via httpx distro==1.8.0 # via orb-billing -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio h11==0.14.0 # via httpcore @@ -30,15 +30,15 @@ httpx==0.25.2 idna==3.4 # via anyio # via httpx -pydantic==2.7.1 +pydantic==2.9.2 # via orb-billing -pydantic-core==2.18.2 +pydantic-core==2.23.4 # via pydantic sniffio==1.3.0 # via anyio # via httpx # via orb-billing -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via anyio # via orb-billing # via pydantic diff --git a/scripts/test b/scripts/test old mode 100644 new mode 100755 diff --git a/src/orb/_base_client.py b/src/orb/_base_client.py index bd3deb81..7a91b0d5 100644 --- a/src/orb/_base_client.py +++ b/src/orb/_base_client.py @@ -144,6 +144,12 @@ def __init__( self.url = url self.params = params + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + return f"{self.__class__.__name__}(params={self.params})" + class BasePage(GenericModel, Generic[_T]): """ @@ -401,14 +407,7 @@ def _make_status_error( ) -> _exceptions.APIStatusError: raise NotImplementedError() - def _remaining_retries( - self, - remaining_retries: Optional[int], - options: FinalRequestOptions, - ) -> int: - return remaining_retries if remaining_retries is not None else options.get_max_retries(self.max_retries) - - def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: + def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: custom_headers = options.headers or {} headers_dict = _merge_mappings(self.default_headers, custom_headers) self._validate_headers(headers_dict, custom_headers) @@ -420,6 +419,11 @@ def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers: if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: headers[idempotency_header] = options.idempotency_key or self._idempotency_key() + # Don't set the retry count header if it was already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + if "x-stainless-retry-count" not in (header.lower() for header in custom_headers): + headers["x-stainless-retry-count"] = str(retries_taken) + return headers def _prepare_url(self, url: str) -> URL: @@ -441,6 +445,8 @@ def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: def _build_request( self, options: FinalRequestOptions, + *, + retries_taken: int = 0, ) -> httpx.Request: if log.isEnabledFor(logging.DEBUG): log.debug("Request options: %s", model_dump(options, exclude_unset=True)) @@ -456,7 +462,7 @@ def _build_request( else: raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - headers = self._build_headers(options) + headers = self._build_headers(options, retries_taken=retries_taken) params = _merge_mappings(self.default_query, options.params) content_type = headers.get("Content-Type") files = options.files @@ -490,12 +496,17 @@ def _build_request( if not files: files = cast(HttpxRequestFiles, ForceMultipartDict()) + prepared_url = self._prepare_url(options.url) + if "_" in prepared_url.host: + # work around https://github.com/encode/httpx/discussions/2880 + kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, method=options.method, - url=self._prepare_url(options.url), + url=prepared_url, # the `Query` type that we use is incompatible with qs' # `Params` type as it needs to be typed as `Mapping[str, object]` # so that passing a `TypedDict` doesn't cause an error. @@ -685,7 +696,8 @@ def _calculate_retry_timeout( if retry_after is not None and 0 < retry_after <= 60: return retry_after - nb_retries = max_retries - remaining_retries + # Also cap retry count to 1000 to avoid any potential overflows with `pow` + nb_retries = min(max_retries - remaining_retries, 1000) # Apply exponential backoff, but not more than the max. sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) @@ -781,6 +793,7 @@ def __init__( custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -793,6 +806,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -802,6 +816,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -845,10 +860,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -934,12 +948,17 @@ def request( stream: bool = False, stream_cls: type[_StreamT] | None = None, ) -> ResponseT | _StreamT: + if remaining_retries is not None: + retries_taken = options.get_max_retries(self.max_retries) - remaining_retries + else: + retries_taken = 0 + return self._request( cast_to=cast_to, options=options, stream=stream, stream_cls=stream_cls, - remaining_retries=remaining_retries, + retries_taken=retries_taken, ) def _request( @@ -947,7 +966,7 @@ def _request( *, cast_to: Type[ResponseT], options: FinalRequestOptions, - remaining_retries: int | None, + retries_taken: int, stream: bool, stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: @@ -959,8 +978,8 @@ def _request( cast_to = self._maybe_override_cast_to(cast_to, options) options = self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + request = self._build_request(options, retries_taken=retries_taken) self._prepare_request(request) kwargs: HttpxSendArgs = {} @@ -978,11 +997,11 @@ def _request( except httpx.TimeoutException as err: log.debug("Encountered httpx.TimeoutException", exc_info=True) - if retries > 0: + if remaining_retries > 0: return self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -993,11 +1012,11 @@ def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries > 0: + if remaining_retries > 0: return self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1020,13 +1039,13 @@ def _request( except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - if retries > 0 and self._should_retry(err.response): + if remaining_retries > 0 and self._should_retry(err.response): err.response.close() return self._retry_request( input_options, cast_to, - retries, - err.response.headers, + retries_taken=retries_taken, + response_headers=err.response.headers, stream=stream, stream_cls=stream_cls, ) @@ -1045,26 +1064,26 @@ def _request( response=response, stream=stream, stream_cls=stream_cls, - retries_taken=options.get_max_retries(self.max_retries) - retries, + retries_taken=retries_taken, ) def _retry_request( self, options: FinalRequestOptions, cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, *, + retries_taken: int, + response_headers: httpx.Headers | None, stream: bool, stream_cls: type[_StreamT] | None, ) -> ResponseT | _StreamT: - remaining = remaining_retries - 1 - if remaining == 1: + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + if remaining_retries == 1: log.debug("1 retry left") else: - log.debug("%i retries left", remaining) + log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) log.info("Retrying request to %s in %f seconds", options.url, timeout) # In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a @@ -1074,7 +1093,7 @@ def _retry_request( return self._request( options=options, cast_to=cast_to, - remaining_retries=remaining, + retries_taken=retries_taken + 1, stream=stream, stream_cls=stream_cls, ) @@ -1356,6 +1375,7 @@ def __init__( custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -1368,6 +1388,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1377,6 +1398,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1420,10 +1442,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -1506,12 +1527,17 @@ async def request( stream_cls: type[_AsyncStreamT] | None = None, remaining_retries: Optional[int] = None, ) -> ResponseT | _AsyncStreamT: + if remaining_retries is not None: + retries_taken = options.get_max_retries(self.max_retries) - remaining_retries + else: + retries_taken = 0 + return await self._request( cast_to=cast_to, options=options, stream=stream, stream_cls=stream_cls, - remaining_retries=remaining_retries, + retries_taken=retries_taken, ) async def _request( @@ -1521,7 +1547,7 @@ async def _request( *, stream: bool, stream_cls: type[_AsyncStreamT] | None, - remaining_retries: int | None, + retries_taken: int, ) -> ResponseT | _AsyncStreamT: if self._platform is None: # `get_platform` can make blocking IO calls so we @@ -1536,8 +1562,8 @@ async def _request( cast_to = self._maybe_override_cast_to(cast_to, options) options = await self._prepare_options(options) - retries = self._remaining_retries(remaining_retries, options) - request = self._build_request(options) + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + request = self._build_request(options, retries_taken=retries_taken) await self._prepare_request(request) kwargs: HttpxSendArgs = {} @@ -1553,11 +1579,11 @@ async def _request( except httpx.TimeoutException as err: log.debug("Encountered httpx.TimeoutException", exc_info=True) - if retries > 0: + if remaining_retries > 0: return await self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1568,11 +1594,11 @@ async def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries > 0: + if remaining_retries > 0: return await self._retry_request( input_options, cast_to, - retries, + retries_taken=retries_taken, stream=stream, stream_cls=stream_cls, response_headers=None, @@ -1590,13 +1616,13 @@ async def _request( except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - if retries > 0 and self._should_retry(err.response): + if remaining_retries > 0 and self._should_retry(err.response): await err.response.aclose() return await self._retry_request( input_options, cast_to, - retries, - err.response.headers, + retries_taken=retries_taken, + response_headers=err.response.headers, stream=stream, stream_cls=stream_cls, ) @@ -1615,26 +1641,26 @@ async def _request( response=response, stream=stream, stream_cls=stream_cls, - retries_taken=options.get_max_retries(self.max_retries) - retries, + retries_taken=retries_taken, ) async def _retry_request( self, options: FinalRequestOptions, cast_to: Type[ResponseT], - remaining_retries: int, - response_headers: httpx.Headers | None, *, + retries_taken: int, + response_headers: httpx.Headers | None, stream: bool, stream_cls: type[_AsyncStreamT] | None, ) -> ResponseT | _AsyncStreamT: - remaining = remaining_retries - 1 - if remaining == 1: + remaining_retries = options.get_max_retries(self.max_retries) - retries_taken + if remaining_retries == 1: log.debug("1 retry left") else: - log.debug("%i retries left", remaining) + log.debug("%i retries left", remaining_retries) - timeout = self._calculate_retry_timeout(remaining, options, response_headers) + timeout = self._calculate_retry_timeout(remaining_retries, options, response_headers) log.info("Retrying request to %s in %f seconds", options.url, timeout) await anyio.sleep(timeout) @@ -1642,7 +1668,7 @@ async def _retry_request( return await self._request( options=options, cast_to=cast_to, - remaining_retries=remaining, + retries_taken=retries_taken + 1, stream=stream, stream_cls=stream_cls, ) diff --git a/src/orb/_compat.py b/src/orb/_compat.py index 21fe6941..92d9ee61 100644 --- a/src/orb/_compat.py +++ b/src/orb/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self +from typing_extensions import Self, Literal import pydantic from pydantic.fields import FieldInfo @@ -133,15 +133,20 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: def model_dump( model: pydantic.BaseModel, *, - exclude: IncEx = None, + exclude: IncEx | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2: + if PYDANTIC_V2 or hasattr(model, "model_dump"): return model.model_dump( + mode=mode, exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, + # warnings are not supported in Pydantic v1 + warnings=warnings if PYDANTIC_V2 else True, ) return cast( "dict[str, Any]", @@ -209,9 +214,6 @@ def __set_name__(self, owner: type[Any], name: str) -> None: ... # __set__ is not defined at runtime, but @cached_property is designed to be settable def __set__(self, instance: object, value: _T) -> None: ... else: - try: - from functools import cached_property as cached_property - except ImportError: - from cached_property import cached_property as cached_property + from functools import cached_property as cached_property typed_cached_property = cached_property diff --git a/src/orb/_legacy_response.py b/src/orb/_legacy_response.py index a808044e..02edaa22 100644 --- a/src/orb/_legacy_response.py +++ b/src/orb/_legacy_response.py @@ -251,6 +251,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) + if cast_to == bool: + return cast(R, response.text.lower() == "true") + origin = get_origin(cast_to) or cast_to if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): diff --git a/src/orb/_models.py b/src/orb/_models.py index d386eaa3..6cb469e2 100644 --- a/src/orb/_models.py +++ b/src/orb/_models.py @@ -37,6 +37,7 @@ PropertyInfo, is_list, is_given, + json_safe, lru_cache, is_mapping, parse_date, @@ -176,7 +177,7 @@ def __str__(self) -> str: # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. @classmethod @override - def construct( + def construct( # pyright: ignore[reportIncompatibleMethodOverride] cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, @@ -248,8 +249,8 @@ def model_dump( self, *, mode: Literal["json", "python"] | str = "python", - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -279,8 +280,8 @@ def model_dump( Returns: A dictionary representation of the model. """ - if mode != "python": - raise ValueError("mode is only supported in Pydantic v2") + if mode not in {"json", "python"}: + raise ValueError("mode must be either 'json' or 'python'") if round_trip != False: raise ValueError("round_trip is only supported in Pydantic v2") if warnings != True: @@ -289,7 +290,7 @@ def model_dump( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") - return super().dict( # pyright: ignore[reportDeprecated] + dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, by_alias=by_alias, @@ -298,13 +299,15 @@ def model_dump( exclude_none=exclude_none, ) + return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + @override def model_dump_json( self, *, indent: int | None = None, - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, diff --git a/src/orb/_response.py b/src/orb/_response.py index bde0a041..5b17754b 100644 --- a/src/orb/_response.py +++ b/src/orb/_response.py @@ -192,6 +192,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) + if cast_to == bool: + return cast(R, response.text.lower() == "true") + origin = get_origin(cast_to) or cast_to # handle the legacy binary response case diff --git a/src/orb/_types.py b/src/orb/_types.py index a6120d6a..de4bcc59 100644 --- a/src/orb/_types.py +++ b/src/orb/_types.py @@ -16,7 +16,7 @@ Optional, Sequence, ) -from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable import httpx import pydantic @@ -195,7 +195,9 @@ def get(self, __key: str) -> str | None: ... # Note: copied from Pydantic # https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49 -IncEx: TypeAlias = "set[int] | set[str] | dict[int, Any] | dict[str, Any] | None" +IncEx: TypeAlias = Union[ + Set[int], Set[str], Mapping[int, Union["IncEx", Literal[True]]], Mapping[str, Union["IncEx", Literal[True]]] +] PostParser = Callable[[Any], Any] diff --git a/src/orb/_utils/__init__.py b/src/orb/_utils/__init__.py index 3efe66c8..a7cff3c0 100644 --- a/src/orb/_utils/__init__.py +++ b/src/orb/_utils/__init__.py @@ -6,6 +6,7 @@ is_list as is_list, is_given as is_given, is_tuple as is_tuple, + json_safe as json_safe, lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, diff --git a/src/orb/_utils/_sync.py b/src/orb/_utils/_sync.py index d0d81033..8b3aaf2b 100644 --- a/src/orb/_utils/_sync.py +++ b/src/orb/_utils/_sync.py @@ -1,56 +1,62 @@ from __future__ import annotations +import sys +import asyncio import functools -from typing import TypeVar, Callable, Awaitable +import contextvars +from typing import Any, TypeVar, Callable, Awaitable from typing_extensions import ParamSpec -import anyio -import anyio.to_thread - -from ._reflection import function_has_argument - T_Retval = TypeVar("T_Retval") T_ParamSpec = ParamSpec("T_ParamSpec") -# copied from `asyncer`, https://github.com/tiangolo/asyncer -def asyncify( - function: Callable[T_ParamSpec, T_Retval], - *, - cancellable: bool = False, - limiter: anyio.CapacityLimiter | None = None, -) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: +if sys.version_info >= (3, 9): + to_thread = asyncio.to_thread +else: + # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread + # for Python 3.8 support + async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs + ) -> Any: + """Asynchronously run function *func* in a separate thread. + + Any *args and **kwargs supplied for this function are directly passed + to *func*. Also, the current :class:`contextvars.Context` is propagated, + allowing context variables from the main thread to be accessed in the + separate thread. + + Returns a coroutine that can be awaited to get the eventual result of *func*. + """ + loop = asyncio.events.get_running_loop() + ctx = contextvars.copy_context() + func_call = functools.partial(ctx.run, func, *args, **kwargs) + return await loop.run_in_executor(None, func_call) + + +# inspired by `asyncer`, https://github.com/tiangolo/asyncer +def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ Take a blocking function and create an async one that receives the same - positional and keyword arguments, and that when called, calls the original function - in a worker thread using `anyio.to_thread.run_sync()`. Internally, - `asyncer.asyncify()` uses the same `anyio.to_thread.run_sync()`, but it supports - keyword arguments additional to positional arguments and it adds better support for - autocompletion and inline errors for the arguments of the function called and the - return value. - - If the `cancellable` option is enabled and the task waiting for its completion is - cancelled, the thread will still run its course but its return value (or any raised - exception) will be ignored. + positional and keyword arguments. For python version 3.9 and above, it uses + asyncio.to_thread to run the function in a separate thread. For python version + 3.8, it uses locally defined copy of the asyncio.to_thread function which was + introduced in python 3.9. - Use it like this: + Usage: - ```Python - def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: - # Do work - return "Some result" + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result - result = await to_thread.asyncify(do_work)("spam", "ham", kwarg1="a", kwarg2="b") - print(result) + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) ``` ## Arguments `function`: a blocking regular callable (e.g. a function) - `cancellable`: `True` to allow cancellation of the operation - `limiter`: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) ## Return @@ -60,22 +66,6 @@ def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: """ async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - partial_f = functools.partial(function, *args, **kwargs) - - # In `v4.1.0` anyio added the `abandon_on_cancel` argument and deprecated the old - # `cancellable` argument, so we need to use the new `abandon_on_cancel` to avoid - # surfacing deprecation warnings. - if function_has_argument(anyio.to_thread.run_sync, "abandon_on_cancel"): - return await anyio.to_thread.run_sync( - partial_f, - abandon_on_cancel=cancellable, - limiter=limiter, - ) - - return await anyio.to_thread.run_sync( - partial_f, - cancellable=cancellable, - limiter=limiter, - ) + return await to_thread(function, *args, **kwargs) return wrapper diff --git a/src/orb/_utils/_transform.py b/src/orb/_utils/_transform.py index 71f35299..a6b62cad 100644 --- a/src/orb/_utils/_transform.py +++ b/src/orb/_utils/_transform.py @@ -173,6 +173,11 @@ def _transform_recursive( # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) ): + # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually + # intended as an iterable, so we don't transform it. + if isinstance(data, dict): + return cast(object, data) + inner_type = extract_type_arg(stripped_type, 0) return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] @@ -186,7 +191,7 @@ def _transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: @@ -329,7 +334,7 @@ async def _async_transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: diff --git a/src/orb/_utils/_utils.py b/src/orb/_utils/_utils.py index 2fc5a1c6..e5811bba 100644 --- a/src/orb/_utils/_utils.py +++ b/src/orb/_utils/_utils.py @@ -16,6 +16,7 @@ overload, ) from pathlib import Path +from datetime import date, datetime from typing_extensions import TypeGuard import sniffio @@ -363,12 +364,13 @@ def file_from_path(path: str) -> FileTypes: def get_required_header(headers: HeadersLike, header: str) -> str: lower_header = header.lower() - if isinstance(headers, Mapping): - for k, v in headers.items(): + if is_mapping_t(headers): + # mypy doesn't understand the type narrowing here + for k, v in headers.items(): # type: ignore if k.lower() == lower_header and isinstance(v, str): return v - """ to deal with the case where the header looks like Stainless-Event-Id """ + # to deal with the case where the header looks like Stainless-Event-Id intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) for normalized_header in [header, lower_header, header.upper(), intercaps_header]: @@ -394,3 +396,19 @@ def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: maxsize=maxsize, ) return cast(Any, wrapper) # type: ignore[no-any-return] + + +def json_safe(data: object) -> object: + """Translates a mapping / sequence recursively in the same fashion + as `pydantic` v2's `model_dump(mode="json")`. + """ + if is_mapping(data): + return {json_safe(key): json_safe(value) for key, value in data.items()} + + if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): + return [json_safe(item) for item in data] + + if isinstance(data, (datetime, date)): + return data.isoformat() + + return data diff --git a/src/orb/_version.py b/src/orb/_version.py index 5826d194..a619f812 100644 --- a/src/orb/_version.py +++ b/src/orb/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "orb" -__version__ = "2.16.0" # x-release-please-version +__version__ = "2.17.0" # x-release-please-version diff --git a/src/orb/resources/__init__.py b/src/orb/resources/__init__.py index b248b84f..f5515f6c 100644 --- a/src/orb/resources/__init__.py +++ b/src/orb/resources/__init__.py @@ -64,6 +64,10 @@ InvoicesWithStreamingResponse, AsyncInvoicesWithStreamingResponse, ) +from .webhooks import ( + Webhooks, + AsyncWebhooks, +) from .customers import ( Customers, AsyncCustomers, @@ -104,10 +108,6 @@ InvoiceLineItemsWithStreamingResponse, AsyncInvoiceLineItemsWithStreamingResponse, ) -from .webhooks import ( - Webhooks, - AsyncWebhooks, -) __all__ = [ "TopLevel", diff --git a/src/orb/resources/alerts.py b/src/orb/resources/alerts.py index c168f120..36f800fa 100644 --- a/src/orb/resources/alerts.py +++ b/src/orb/resources/alerts.py @@ -34,10 +34,21 @@ class Alerts(SyncAPIResource): @cached_property def with_raw_response(self) -> AlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AlertsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AlertsWithStreamingResponse(self) def retrieve( @@ -504,10 +515,21 @@ def enable( class AsyncAlerts(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAlertsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncAlertsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncAlertsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncAlertsWithStreamingResponse(self) async def retrieve( diff --git a/src/orb/resources/coupons/coupons.py b/src/orb/resources/coupons/coupons.py index 74d8d9f0..25f16dd1 100644 --- a/src/orb/resources/coupons/coupons.py +++ b/src/orb/resources/coupons/coupons.py @@ -38,10 +38,21 @@ def subscriptions(self) -> Subscriptions: @cached_property def with_raw_response(self) -> CouponsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return CouponsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CouponsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return CouponsWithStreamingResponse(self) def create( @@ -252,10 +263,21 @@ def subscriptions(self) -> AsyncSubscriptions: @cached_property def with_raw_response(self) -> AsyncCouponsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncCouponsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCouponsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncCouponsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/coupons/subscriptions.py b/src/orb/resources/coupons/subscriptions.py index a4184554..30eca546 100644 --- a/src/orb/resources/coupons/subscriptions.py +++ b/src/orb/resources/coupons/subscriptions.py @@ -23,10 +23,21 @@ class Subscriptions(SyncAPIResource): @cached_property def with_raw_response(self) -> SubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return SubscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> SubscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return SubscriptionsWithStreamingResponse(self) def list( @@ -87,10 +98,21 @@ def list( class AsyncSubscriptions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncSubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncSubscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncSubscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncSubscriptionsWithStreamingResponse(self) def list( diff --git a/src/orb/resources/credit_notes.py b/src/orb/resources/credit_notes.py index c4aa0f94..36bfe3c9 100644 --- a/src/orb/resources/credit_notes.py +++ b/src/orb/resources/credit_notes.py @@ -2,14 +2,18 @@ from __future__ import annotations -from typing import Optional +from typing import Iterable, Optional +from typing_extensions import Literal import httpx from .. import _legacy_response -from ..types import credit_note_list_params +from ..types import credit_note_list_params, credit_note_create_params from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from .._utils import maybe_transform +from .._utils import ( + maybe_transform, + async_maybe_transform, +) from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper @@ -23,12 +27,77 @@ class CreditNotes(SyncAPIResource): @cached_property def with_raw_response(self) -> CreditNotesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return CreditNotesWithRawResponse(self) @cached_property def with_streaming_response(self) -> CreditNotesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return CreditNotesWithStreamingResponse(self) + def create( + self, + *, + line_items: Iterable[credit_note_create_params.LineItem], + memo: Optional[str] | NotGiven = NOT_GIVEN, + reason: Optional[Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"]] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> CreditNote: + """ + This endpoint is used to create a single + [`Credit Note`](../guides/invoicing/credit-notes). + + Args: + memo: An optional memo to attach to the credit note. + + reason: An optional reason for the credit note. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + return self._post( + "/credit_notes", + body=maybe_transform( + { + "line_items": line_items, + "memo": memo, + "reason": reason, + }, + credit_note_create_params.CreditNoteCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=CreditNote, + ) + def list( self, *, @@ -118,12 +187,77 @@ def fetch( class AsyncCreditNotes(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCreditNotesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncCreditNotesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCreditNotesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncCreditNotesWithStreamingResponse(self) + async def create( + self, + *, + line_items: Iterable[credit_note_create_params.LineItem], + memo: Optional[str] | NotGiven = NOT_GIVEN, + reason: Optional[Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"]] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> CreditNote: + """ + This endpoint is used to create a single + [`Credit Note`](../guides/invoicing/credit-notes). + + Args: + memo: An optional memo to attach to the credit note. + + reason: An optional reason for the credit note. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + return await self._post( + "/credit_notes", + body=await async_maybe_transform( + { + "line_items": line_items, + "memo": memo, + "reason": reason, + }, + credit_note_create_params.CreditNoteCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=CreditNote, + ) + def list( self, *, @@ -214,6 +348,9 @@ class CreditNotesWithRawResponse: def __init__(self, credit_notes: CreditNotes) -> None: self._credit_notes = credit_notes + self.create = _legacy_response.to_raw_response_wrapper( + credit_notes.create, + ) self.list = _legacy_response.to_raw_response_wrapper( credit_notes.list, ) @@ -226,6 +363,9 @@ class AsyncCreditNotesWithRawResponse: def __init__(self, credit_notes: AsyncCreditNotes) -> None: self._credit_notes = credit_notes + self.create = _legacy_response.async_to_raw_response_wrapper( + credit_notes.create, + ) self.list = _legacy_response.async_to_raw_response_wrapper( credit_notes.list, ) @@ -238,6 +378,9 @@ class CreditNotesWithStreamingResponse: def __init__(self, credit_notes: CreditNotes) -> None: self._credit_notes = credit_notes + self.create = to_streamed_response_wrapper( + credit_notes.create, + ) self.list = to_streamed_response_wrapper( credit_notes.list, ) @@ -250,6 +393,9 @@ class AsyncCreditNotesWithStreamingResponse: def __init__(self, credit_notes: AsyncCreditNotes) -> None: self._credit_notes = credit_notes + self.create = async_to_streamed_response_wrapper( + credit_notes.create, + ) self.list = async_to_streamed_response_wrapper( credit_notes.list, ) diff --git a/src/orb/resources/customers/balance_transactions.py b/src/orb/resources/customers/balance_transactions.py index dfc7c425..2ac30eea 100644 --- a/src/orb/resources/customers/balance_transactions.py +++ b/src/orb/resources/customers/balance_transactions.py @@ -29,10 +29,21 @@ class BalanceTransactions(SyncAPIResource): @cached_property def with_raw_response(self) -> BalanceTransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return BalanceTransactionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> BalanceTransactionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return BalanceTransactionsWithStreamingResponse(self) def create( @@ -179,10 +190,21 @@ def list( class AsyncBalanceTransactions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBalanceTransactionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncBalanceTransactionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncBalanceTransactionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncBalanceTransactionsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/customers/costs.py b/src/orb/resources/customers/costs.py index 4315389e..35aafef7 100644 --- a/src/orb/resources/customers/costs.py +++ b/src/orb/resources/customers/costs.py @@ -28,10 +28,21 @@ class Costs(SyncAPIResource): @cached_property def with_raw_response(self) -> CostsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return CostsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CostsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return CostsWithStreamingResponse(self) def list( @@ -161,23 +172,6 @@ def list( You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - ## Grouping by custom attributes - - In order to view costs grouped by a specific _attribute_ that each event is - tagged with (i.e. `cluster`), you can additionally specify a `group_by` key. The - `group_by` key denotes the event property on which to group. - - When returning grouped costs, a separate `price_group` object in the - `per_price_costs` array is returned for each value of the `group_by` key present - in your events. The `subtotal` value of the `per_price_costs` object is the sum - of each `price_group`'s total. - - Orb expects events will contain values in the `properties` dictionary that - correspond to the `group_by` key specified. By default, Orb will return a `null` - group (i.e. events that match the metric but do not have the key set). - Currently, it is only possible to view costs grouped by a single attribute at a - time. - ### Matrix prices When a price uses matrix pricing, it's important to view costs grouped by those @@ -354,23 +348,6 @@ def list_by_external_id( You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - ## Grouping by custom attributes - - In order to view costs grouped by a specific _attribute_ that each event is - tagged with (i.e. `cluster`), you can additionally specify a `group_by` key. The - `group_by` key denotes the event property on which to group. - - When returning grouped costs, a separate `price_group` object in the - `per_price_costs` array is returned for each value of the `group_by` key present - in your events. The `subtotal` value of the `per_price_costs` object is the sum - of each `price_group`'s total. - - Orb expects events will contain values in the `properties` dictionary that - correspond to the `group_by` key specified. By default, Orb will return a `null` - group (i.e. events that match the metric but do not have the key set). - Currently, it is only possible to view costs grouped by a single attribute at a - time. - ### Matrix prices When a price uses matrix pricing, it's important to view costs grouped by those @@ -426,10 +403,21 @@ def list_by_external_id( class AsyncCosts(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCostsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncCostsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCostsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncCostsWithStreamingResponse(self) async def list( @@ -559,23 +547,6 @@ async def list( You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - ## Grouping by custom attributes - - In order to view costs grouped by a specific _attribute_ that each event is - tagged with (i.e. `cluster`), you can additionally specify a `group_by` key. The - `group_by` key denotes the event property on which to group. - - When returning grouped costs, a separate `price_group` object in the - `per_price_costs` array is returned for each value of the `group_by` key present - in your events. The `subtotal` value of the `per_price_costs` object is the sum - of each `price_group`'s total. - - Orb expects events will contain values in the `properties` dictionary that - correspond to the `group_by` key specified. By default, Orb will return a `null` - group (i.e. events that match the metric but do not have the key set). - Currently, it is only possible to view costs grouped by a single attribute at a - time. - ### Matrix prices When a price uses matrix pricing, it's important to view costs grouped by those @@ -752,23 +723,6 @@ async def list_by_external_id( You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - ## Grouping by custom attributes - - In order to view costs grouped by a specific _attribute_ that each event is - tagged with (i.e. `cluster`), you can additionally specify a `group_by` key. The - `group_by` key denotes the event property on which to group. - - When returning grouped costs, a separate `price_group` object in the - `per_price_costs` array is returned for each value of the `group_by` key present - in your events. The `subtotal` value of the `per_price_costs` object is the sum - of each `price_group`'s total. - - Orb expects events will contain values in the `properties` dictionary that - correspond to the `group_by` key specified. By default, Orb will return a `null` - group (i.e. events that match the metric but do not have the key set). - Currently, it is only possible to view costs grouped by a single attribute at a - time. - ### Matrix prices When a price uses matrix pricing, it's important to view costs grouped by those diff --git a/src/orb/resources/customers/credits/credits.py b/src/orb/resources/customers/credits/credits.py index 6167390b..2fd36621 100644 --- a/src/orb/resources/customers/credits/credits.py +++ b/src/orb/resources/customers/credits/credits.py @@ -48,10 +48,21 @@ def top_ups(self) -> TopUps: @cached_property def with_raw_response(self) -> CreditsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return CreditsWithRawResponse(self) @cached_property def with_streaming_response(self) -> CreditsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return CreditsWithStreamingResponse(self) def list( @@ -192,10 +203,21 @@ def top_ups(self) -> AsyncTopUps: @cached_property def with_raw_response(self) -> AsyncCreditsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncCreditsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCreditsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncCreditsWithStreamingResponse(self) def list( diff --git a/src/orb/resources/customers/credits/ledger.py b/src/orb/resources/customers/credits/ledger.py index f9853958..84815e8a 100644 --- a/src/orb/resources/customers/credits/ledger.py +++ b/src/orb/resources/customers/credits/ledger.py @@ -2,9 +2,9 @@ from __future__ import annotations -from typing import Any, Dict, Union, Optional, cast, overload +from typing import Any, Dict, Union, Optional, cast from datetime import date, datetime -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx @@ -39,10 +39,21 @@ class Ledger(SyncAPIResource): @cached_property def with_raw_response(self) -> LedgerWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return LedgerWithRawResponse(self) @cached_property def with_streaming_response(self) -> LedgerWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return LedgerWithStreamingResponse(self) def list( @@ -2157,10 +2168,21 @@ def list_by_external_id( class AsyncLedger(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncLedgerWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncLedgerWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncLedgerWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncLedgerWithStreamingResponse(self) def list( diff --git a/src/orb/resources/customers/credits/top_ups.py b/src/orb/resources/customers/credits/top_ups.py index 111fa566..58d7526f 100644 --- a/src/orb/resources/customers/credits/top_ups.py +++ b/src/orb/resources/customers/credits/top_ups.py @@ -35,10 +35,21 @@ class TopUps(SyncAPIResource): @cached_property def with_raw_response(self) -> TopUpsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return TopUpsWithRawResponse(self) @cached_property def with_streaming_response(self) -> TopUpsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return TopUpsWithStreamingResponse(self) def create( @@ -407,10 +418,21 @@ def list_by_external_id( class AsyncTopUps(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTopUpsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncTopUpsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncTopUpsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncTopUpsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/customers/customers.py b/src/orb/resources/customers/customers.py index b8603320..e584c033 100644 --- a/src/orb/resources/customers/customers.py +++ b/src/orb/resources/customers/customers.py @@ -70,10 +70,21 @@ def balance_transactions(self) -> BalanceTransactions: @cached_property def with_raw_response(self) -> CustomersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return CustomersWithRawResponse(self) @cached_property def with_streaming_response(self) -> CustomersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return CustomersWithStreamingResponse(self) def create( @@ -95,6 +106,7 @@ def create( payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, reporting_configuration: Optional[customer_create_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_create_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_create_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_create_params.TaxID] | NotGiven = NOT_GIVEN, timezone: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -289,6 +301,7 @@ def create( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, "timezone": timezone, }, @@ -324,6 +337,7 @@ def update( payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, reporting_configuration: Optional[customer_update_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_update_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_update_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_update_params.TaxID] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -509,6 +523,7 @@ def update( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, }, customer_update_params.CustomerUpdateParams, @@ -599,10 +614,11 @@ def delete( idempotency_key: str | None = None, ) -> None: """ - This performs a deletion of this customer, its subscriptions, and its invoices. - This operation is irreversible. Note that this is a _soft_ deletion, but the - data will be inaccessible through the API and Orb dashboard. For hard-deletion, - please reach out to the Orb team directly. + This performs a deletion of this customer, its subscriptions, and its invoices, + provided the customer does not have any issued invoices. Customers with issued + invoices cannot be deleted. This operation is irreversible. Note that this is a + _soft_ deletion, but the data will be inaccessible through the API and Orb + dashboard. For a hard-deletion, please reach out to the Orb team directly. **Note**: This operation happens asynchronously and can be expected to take a few minutes to propagate to related resources. However, querying for the @@ -737,6 +753,7 @@ def update_by_external_id( reporting_configuration: Optional[customer_update_by_external_id_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_update_by_external_id_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_update_by_external_id_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_update_by_external_id_params.TaxID] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -921,6 +938,7 @@ def update_by_external_id( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, }, customer_update_by_external_id_params.CustomerUpdateByExternalIDParams, @@ -951,10 +969,21 @@ def balance_transactions(self) -> AsyncBalanceTransactions: @cached_property def with_raw_response(self) -> AsyncCustomersWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncCustomersWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncCustomersWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncCustomersWithStreamingResponse(self) async def create( @@ -976,6 +1005,7 @@ async def create( payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, reporting_configuration: Optional[customer_create_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_create_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_create_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_create_params.TaxID] | NotGiven = NOT_GIVEN, timezone: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1170,6 +1200,7 @@ async def create( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, "timezone": timezone, }, @@ -1205,6 +1236,7 @@ async def update( payment_provider_id: Optional[str] | NotGiven = NOT_GIVEN, reporting_configuration: Optional[customer_update_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_update_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_update_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_update_params.TaxID] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1390,6 +1422,7 @@ async def update( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, }, customer_update_params.CustomerUpdateParams, @@ -1480,10 +1513,11 @@ async def delete( idempotency_key: str | None = None, ) -> None: """ - This performs a deletion of this customer, its subscriptions, and its invoices. - This operation is irreversible. Note that this is a _soft_ deletion, but the - data will be inaccessible through the API and Orb dashboard. For hard-deletion, - please reach out to the Orb team directly. + This performs a deletion of this customer, its subscriptions, and its invoices, + provided the customer does not have any issued invoices. Customers with issued + invoices cannot be deleted. This operation is irreversible. Note that this is a + _soft_ deletion, but the data will be inaccessible through the API and Orb + dashboard. For a hard-deletion, please reach out to the Orb team directly. **Note**: This operation happens asynchronously and can be expected to take a few minutes to propagate to related resources. However, querying for the @@ -1618,6 +1652,7 @@ async def update_by_external_id( reporting_configuration: Optional[customer_update_by_external_id_params.ReportingConfiguration] | NotGiven = NOT_GIVEN, shipping_address: Optional[customer_update_by_external_id_params.ShippingAddress] | NotGiven = NOT_GIVEN, + tax_configuration: Optional[customer_update_by_external_id_params.TaxConfiguration] | NotGiven = NOT_GIVEN, tax_id: Optional[customer_update_by_external_id_params.TaxID] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1802,6 +1837,7 @@ async def update_by_external_id( "payment_provider_id": payment_provider_id, "reporting_configuration": reporting_configuration, "shipping_address": shipping_address, + "tax_configuration": tax_configuration, "tax_id": tax_id, }, customer_update_by_external_id_params.CustomerUpdateByExternalIDParams, diff --git a/src/orb/resources/events/__init__.py b/src/orb/resources/events/__init__.py index ead1b010..fb5b67ac 100644 --- a/src/orb/resources/events/__init__.py +++ b/src/orb/resources/events/__init__.py @@ -8,6 +8,14 @@ EventsWithStreamingResponse, AsyncEventsWithStreamingResponse, ) +from .volume import ( + Volume, + AsyncVolume, + VolumeWithRawResponse, + AsyncVolumeWithRawResponse, + VolumeWithStreamingResponse, + AsyncVolumeWithStreamingResponse, +) from .backfills import ( Backfills, AsyncBackfills, @@ -24,6 +32,12 @@ "AsyncBackfillsWithRawResponse", "BackfillsWithStreamingResponse", "AsyncBackfillsWithStreamingResponse", + "Volume", + "AsyncVolume", + "VolumeWithRawResponse", + "AsyncVolumeWithRawResponse", + "VolumeWithStreamingResponse", + "AsyncVolumeWithStreamingResponse", "Events", "AsyncEvents", "EventsWithRawResponse", diff --git a/src/orb/resources/events/backfills.py b/src/orb/resources/events/backfills.py index e742f6d5..112f7807 100644 --- a/src/orb/resources/events/backfills.py +++ b/src/orb/resources/events/backfills.py @@ -31,10 +31,21 @@ class Backfills(SyncAPIResource): @cached_property def with_raw_response(self) -> BackfillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return BackfillsWithRawResponse(self) @cached_property def with_streaming_response(self) -> BackfillsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return BackfillsWithStreamingResponse(self) def create( @@ -101,13 +112,15 @@ def create( backfill will automatically begin reflecting throughout Orb at the close time. If not specified, it will default to 1 day after the creation of the backfill. - customer_id: The ID of the customer to which this backfill is scoped. + customer_id: The Orb-generated ID of the customer to which this backfill is scoped. Omitting + this field will scope the backfill to all customers. deprecation_filter: A boolean [computed property](../guides/extensibility/advanced-metrics#computed-properties) used to filter the set of events to deprecate external_customer_id: The external customer ID of the customer to which this backfill is scoped. + Omitting this field will scope the backfill to all customers. replace_existing_events: If true, replaces all existing events in the timeframe with the newly ingested events. If false, adds the newly ingested events to the existing events. @@ -328,10 +341,21 @@ def revert( class AsyncBackfills(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBackfillsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncBackfillsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncBackfillsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncBackfillsWithStreamingResponse(self) async def create( @@ -398,13 +422,15 @@ async def create( backfill will automatically begin reflecting throughout Orb at the close time. If not specified, it will default to 1 day after the creation of the backfill. - customer_id: The ID of the customer to which this backfill is scoped. + customer_id: The Orb-generated ID of the customer to which this backfill is scoped. Omitting + this field will scope the backfill to all customers. deprecation_filter: A boolean [computed property](../guides/extensibility/advanced-metrics#computed-properties) used to filter the set of events to deprecate external_customer_id: The external customer ID of the customer to which this backfill is scoped. + Omitting this field will scope the backfill to all customers. replace_existing_events: If true, replaces all existing events in the timeframe with the newly ingested events. If false, adds the newly ingested events to the existing events. diff --git a/src/orb/resources/events/events.py b/src/orb/resources/events/events.py index 0c7edc7b..3d4efed8 100644 --- a/src/orb/resources/events/events.py +++ b/src/orb/resources/events/events.py @@ -8,6 +8,14 @@ import httpx from ... import _legacy_response +from .volume import ( + Volume, + AsyncVolume, + VolumeWithRawResponse, + AsyncVolumeWithRawResponse, + VolumeWithStreamingResponse, + AsyncVolumeWithStreamingResponse, +) from ...types import event_ingest_params, event_search_params, event_update_params from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven from ..._utils import ( @@ -39,12 +47,27 @@ class Events(SyncAPIResource): def backfills(self) -> Backfills: return Backfills(self._client) + @cached_property + def volume(self) -> Volume: + return Volume(self._client) + @cached_property def with_raw_response(self) -> EventsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return EventsWithRawResponse(self) @cached_property def with_streaming_response(self) -> EventsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return EventsWithStreamingResponse(self) def update( @@ -573,12 +596,27 @@ class AsyncEvents(AsyncAPIResource): def backfills(self) -> AsyncBackfills: return AsyncBackfills(self._client) + @cached_property + def volume(self) -> AsyncVolume: + return AsyncVolume(self._client) + @cached_property def with_raw_response(self) -> AsyncEventsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncEventsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncEventsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncEventsWithStreamingResponse(self) async def update( @@ -1123,6 +1161,10 @@ def __init__(self, events: Events) -> None: def backfills(self) -> BackfillsWithRawResponse: return BackfillsWithRawResponse(self._events.backfills) + @cached_property + def volume(self) -> VolumeWithRawResponse: + return VolumeWithRawResponse(self._events.volume) + class AsyncEventsWithRawResponse: def __init__(self, events: AsyncEvents) -> None: @@ -1145,6 +1187,10 @@ def __init__(self, events: AsyncEvents) -> None: def backfills(self) -> AsyncBackfillsWithRawResponse: return AsyncBackfillsWithRawResponse(self._events.backfills) + @cached_property + def volume(self) -> AsyncVolumeWithRawResponse: + return AsyncVolumeWithRawResponse(self._events.volume) + class EventsWithStreamingResponse: def __init__(self, events: Events) -> None: @@ -1167,6 +1213,10 @@ def __init__(self, events: Events) -> None: def backfills(self) -> BackfillsWithStreamingResponse: return BackfillsWithStreamingResponse(self._events.backfills) + @cached_property + def volume(self) -> VolumeWithStreamingResponse: + return VolumeWithStreamingResponse(self._events.volume) + class AsyncEventsWithStreamingResponse: def __init__(self, events: AsyncEvents) -> None: @@ -1188,3 +1238,7 @@ def __init__(self, events: AsyncEvents) -> None: @cached_property def backfills(self) -> AsyncBackfillsWithStreamingResponse: return AsyncBackfillsWithStreamingResponse(self._events.backfills) + + @cached_property + def volume(self) -> AsyncVolumeWithStreamingResponse: + return AsyncVolumeWithStreamingResponse(self._events.volume) diff --git a/src/orb/resources/events/volume.py b/src/orb/resources/events/volume.py new file mode 100644 index 00000000..ff4e223b --- /dev/null +++ b/src/orb/resources/events/volume.py @@ -0,0 +1,247 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime + +import httpx + +from ... import _legacy_response +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper +from ..._base_client import make_request_options +from ...types.events import volume_list_params +from ...types.events.event_volumes import EventVolumes + +__all__ = ["Volume", "AsyncVolume"] + + +class Volume(SyncAPIResource): + @cached_property + def with_raw_response(self) -> VolumeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ + return VolumeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VolumeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ + return VolumeWithStreamingResponse(self) + + def list( + self, + *, + timeframe_start: Union[str, datetime], + cursor: Optional[str] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EventVolumes: + """ + This endpoint returns the event volume for an account in a + [paginated list format](../reference/pagination). + + The event volume is aggregated by the hour and the + [timestamp](../reference/ingest#determining-event-timestamp) field is used to + determine which hour an event is associated with. Note, this means that + late-arriving events increment the volume count for the hour window the + timestamp is in, not the latest hour window. + + Each item in the response contains the count of events aggregated by the hour + where the start and end time are hour-aligned and in UTC. When a specific + timestamp is passed in for either start or end time, the response includes the + hours the timestamp falls in. + + Args: + timeframe_start: The start of the timeframe, inclusive, in which to return event volume. All + datetime values are converted to UTC time. If the specified time isn't + hour-aligned, the response includes the event volume count for the hour the time + falls in. + + cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned + from the initial request. + + limit: The number of items to fetch. Defaults to 20. + + timeframe_end: The end of the timeframe, exclusive, in which to return event volume. If not + specified, the current time is used. All datetime values are converted to UTC + time.If the specified time isn't hour-aligned, the response includes the event + volumecount for the hour the time falls in. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/events/volume", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "timeframe_start": timeframe_start, + "cursor": cursor, + "limit": limit, + "timeframe_end": timeframe_end, + }, + volume_list_params.VolumeListParams, + ), + ), + cast_to=EventVolumes, + ) + + +class AsyncVolume(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncVolumeWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ + return AsyncVolumeWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVolumeWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ + return AsyncVolumeWithStreamingResponse(self) + + async def list( + self, + *, + timeframe_start: Union[str, datetime], + cursor: Optional[str] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + timeframe_end: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> EventVolumes: + """ + This endpoint returns the event volume for an account in a + [paginated list format](../reference/pagination). + + The event volume is aggregated by the hour and the + [timestamp](../reference/ingest#determining-event-timestamp) field is used to + determine which hour an event is associated with. Note, this means that + late-arriving events increment the volume count for the hour window the + timestamp is in, not the latest hour window. + + Each item in the response contains the count of events aggregated by the hour + where the start and end time are hour-aligned and in UTC. When a specific + timestamp is passed in for either start or end time, the response includes the + hours the timestamp falls in. + + Args: + timeframe_start: The start of the timeframe, inclusive, in which to return event volume. All + datetime values are converted to UTC time. If the specified time isn't + hour-aligned, the response includes the event volume count for the hour the time + falls in. + + cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned + from the initial request. + + limit: The number of items to fetch. Defaults to 20. + + timeframe_end: The end of the timeframe, exclusive, in which to return event volume. If not + specified, the current time is used. All datetime values are converted to UTC + time.If the specified time isn't hour-aligned, the response includes the event + volumecount for the hour the time falls in. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/events/volume", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "timeframe_start": timeframe_start, + "cursor": cursor, + "limit": limit, + "timeframe_end": timeframe_end, + }, + volume_list_params.VolumeListParams, + ), + ), + cast_to=EventVolumes, + ) + + +class VolumeWithRawResponse: + def __init__(self, volume: Volume) -> None: + self._volume = volume + + self.list = _legacy_response.to_raw_response_wrapper( + volume.list, + ) + + +class AsyncVolumeWithRawResponse: + def __init__(self, volume: AsyncVolume) -> None: + self._volume = volume + + self.list = _legacy_response.async_to_raw_response_wrapper( + volume.list, + ) + + +class VolumeWithStreamingResponse: + def __init__(self, volume: Volume) -> None: + self._volume = volume + + self.list = to_streamed_response_wrapper( + volume.list, + ) + + +class AsyncVolumeWithStreamingResponse: + def __init__(self, volume: AsyncVolume) -> None: + self._volume = volume + + self.list = async_to_streamed_response_wrapper( + volume.list, + ) diff --git a/src/orb/resources/invoice_line_items.py b/src/orb/resources/invoice_line_items.py index 3cc42cab..50ecd4c3 100644 --- a/src/orb/resources/invoice_line_items.py +++ b/src/orb/resources/invoice_line_items.py @@ -26,10 +26,21 @@ class InvoiceLineItems(SyncAPIResource): @cached_property def with_raw_response(self) -> InvoiceLineItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return InvoiceLineItemsWithRawResponse(self) @cached_property def with_streaming_response(self) -> InvoiceLineItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return InvoiceLineItemsWithStreamingResponse(self) def create( @@ -105,10 +116,21 @@ def create( class AsyncInvoiceLineItems(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncInvoiceLineItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncInvoiceLineItemsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncInvoiceLineItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncInvoiceLineItemsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/invoices.py b/src/orb/resources/invoices.py index 6c40a39f..a85c4c11 100644 --- a/src/orb/resources/invoices.py +++ b/src/orb/resources/invoices.py @@ -11,6 +11,7 @@ from .. import _legacy_response from ..types import ( invoice_list_params, + invoice_issue_params, invoice_create_params, invoice_update_params, invoice_mark_paid_params, @@ -36,10 +37,21 @@ class Invoices(SyncAPIResource): @cached_property def with_raw_response(self) -> InvoicesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return InvoicesWithRawResponse(self) @cached_property def with_streaming_response(self) -> InvoicesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return InvoicesWithStreamingResponse(self) def create( @@ -223,6 +235,10 @@ def list( By default, this only returns invoices that are `issued`, `paid`, or `synced`. + When fetching any `draft` invoices, this returns the last-computed invoice + values for each draft invoice, which may not always be up-to-date since Orb + regularly refreshes invoices asynchronously. + Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. @@ -310,7 +326,7 @@ def fetch( def fetch_upcoming( self, *, - subscription_id: str | NotGiven = NOT_GIVEN, + subscription_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -350,6 +366,7 @@ def issue( self, invoice_id: str, *, + synchronous: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -368,6 +385,12 @@ def issue( providers, etc). Args: + synchronous: If true, the invoice will be issued synchronously. If false, the invoice will be + issued asynchronously. The synchronous option is only available for invoices + containin no usage fees. If the invoice is configured to sync to an external + provider, a successful response from this endpoint guarantees the invoice is + present in the provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -382,6 +405,7 @@ def issue( raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return self._post( f"/invoices/{invoice_id}/issue", + body=maybe_transform({"synchronous": synchronous}, invoice_issue_params.InvoiceIssueParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -543,10 +567,21 @@ def void( class AsyncInvoices(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncInvoicesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncInvoicesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncInvoicesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncInvoicesWithStreamingResponse(self) async def create( @@ -730,6 +765,10 @@ def list( By default, this only returns invoices that are `issued`, `paid`, or `synced`. + When fetching any `draft` invoices, this returns the last-computed invoice + values for each draft invoice, which may not always be up-to-date since Orb + regularly refreshes invoices asynchronously. + Args: cursor: Cursor for pagination. This can be populated by the `next_cursor` value returned from the initial request. @@ -817,7 +856,7 @@ async def fetch( async def fetch_upcoming( self, *, - subscription_id: str | NotGiven = NOT_GIVEN, + subscription_id: str, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -857,6 +896,7 @@ async def issue( self, invoice_id: str, *, + synchronous: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -875,6 +915,12 @@ async def issue( providers, etc). Args: + synchronous: If true, the invoice will be issued synchronously. If false, the invoice will be + issued asynchronously. The synchronous option is only available for invoices + containin no usage fees. If the invoice is configured to sync to an external + provider, a successful response from this endpoint guarantees the invoice is + present in the provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -889,6 +935,7 @@ async def issue( raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") return await self._post( f"/invoices/{invoice_id}/issue", + body=await async_maybe_transform({"synchronous": synchronous}, invoice_issue_params.InvoiceIssueParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, diff --git a/src/orb/resources/items.py b/src/orb/resources/items.py index 2121f1de..8f58d945 100644 --- a/src/orb/resources/items.py +++ b/src/orb/resources/items.py @@ -26,10 +26,21 @@ class Items(SyncAPIResource): @cached_property def with_raw_response(self) -> ItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return ItemsWithRawResponse(self) @cached_property def with_streaming_response(self) -> ItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return ItemsWithStreamingResponse(self) def create( @@ -208,10 +219,21 @@ def fetch( class AsyncItems(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncItemsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncItemsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncItemsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncItemsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/metrics.py b/src/orb/resources/metrics.py index 0c60af6b..df5d6516 100644 --- a/src/orb/resources/metrics.py +++ b/src/orb/resources/metrics.py @@ -27,10 +27,21 @@ class Metrics(SyncAPIResource): @cached_property def with_raw_response(self) -> MetricsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return MetricsWithRawResponse(self) @cached_property def with_streaming_response(self) -> MetricsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return MetricsWithStreamingResponse(self) def create( @@ -246,10 +257,21 @@ def fetch( class AsyncMetrics(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncMetricsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncMetricsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncMetricsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncMetricsWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/plans/external_plan_id.py b/src/orb/resources/plans/external_plan_id.py index 9b99ce1d..bc8da0a5 100644 --- a/src/orb/resources/plans/external_plan_id.py +++ b/src/orb/resources/plans/external_plan_id.py @@ -25,10 +25,21 @@ class ExternalPlanID(SyncAPIResource): @cached_property def with_raw_response(self) -> ExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return ExternalPlanIDWithRawResponse(self) @cached_property def with_streaming_response(self) -> ExternalPlanIDWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return ExternalPlanIDWithStreamingResponse(self) def update( @@ -145,10 +156,21 @@ def fetch( class AsyncExternalPlanID(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncExternalPlanIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncExternalPlanIDWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncExternalPlanIDWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncExternalPlanIDWithStreamingResponse(self) async def update( diff --git a/src/orb/resources/plans/plans.py b/src/orb/resources/plans/plans.py index e32f43a5..0c8a1f17 100644 --- a/src/orb/resources/plans/plans.py +++ b/src/orb/resources/plans/plans.py @@ -40,10 +40,21 @@ def external_plan_id(self) -> ExternalPlanID: @cached_property def with_raw_response(self) -> PlansWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return PlansWithRawResponse(self) @cached_property def with_streaming_response(self) -> PlansWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return PlansWithStreamingResponse(self) def create( @@ -304,10 +315,21 @@ def external_plan_id(self) -> AsyncExternalPlanID: @cached_property def with_raw_response(self) -> AsyncPlansWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncPlansWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncPlansWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncPlansWithStreamingResponse(self) async def create( diff --git a/src/orb/resources/prices/external_price_id.py b/src/orb/resources/prices/external_price_id.py index e2ba2682..3afcacde 100644 --- a/src/orb/resources/prices/external_price_id.py +++ b/src/orb/resources/prices/external_price_id.py @@ -25,10 +25,21 @@ class ExternalPriceID(SyncAPIResource): @cached_property def with_raw_response(self) -> ExternalPriceIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return ExternalPriceIDWithRawResponse(self) @cached_property def with_streaming_response(self) -> ExternalPriceIDWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return ExternalPriceIDWithStreamingResponse(self) def update( @@ -128,10 +139,21 @@ def fetch( class AsyncExternalPriceID(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncExternalPriceIDWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncExternalPriceIDWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncExternalPriceIDWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncExternalPriceIDWithStreamingResponse(self) async def update( diff --git a/src/orb/resources/prices/prices.py b/src/orb/resources/prices/prices.py index 734e65ba..79cfe6f3 100644 --- a/src/orb/resources/prices/prices.py +++ b/src/orb/resources/prices/prices.py @@ -2,9 +2,9 @@ from __future__ import annotations -from typing import Any, Dict, List, Union, Optional, cast, overload +from typing import Any, Dict, List, Union, Optional, cast from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, overload import httpx @@ -42,10 +42,21 @@ def external_price_id(self) -> ExternalPriceID: @cached_property def with_raw_response(self) -> PricesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return PricesWithRawResponse(self) @cached_property def with_streaming_response(self) -> PricesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return PricesWithStreamingResponse(self) @overload @@ -1858,6 +1869,190 @@ def create( """ ... + @overload + def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + grouped_with_metered_minimum_config: Dict[str, object], + item_id: str, + model_type: Literal["grouped_with_metered_minimum"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """This endpoint is used to create a [price](../reference/price). + + A price created + using this endpoint is always an add-on, meaning that it’s not associated with a + specific plan and can instead be individually added to subscriptions, including + subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](../reference/price) for the specification of different + price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + + @overload + def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + matrix_with_display_name_config: Dict[str, object], + model_type: Literal["matrix_with_display_name"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """This endpoint is used to create a [price](../reference/price). + + A price created + using this endpoint is always an add-on, meaning that it’s not associated with a + specific plan and can instead be individually added to subscriptions, including + subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](../reference/price) for the specification of different + price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + @overload def create( self, @@ -2063,6 +2258,8 @@ def create( ["cadence", "currency", "item_id", "model_type", "name", "unit_with_proration_config"], ["cadence", "currency", "grouped_allocation_config", "item_id", "model_type", "name"], ["cadence", "currency", "grouped_with_prorated_minimum_config", "item_id", "model_type", "name"], + ["cadence", "currency", "grouped_with_metered_minimum_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_display_name_config", "model_type", "name"], ["bulk_with_proration_config", "cadence", "currency", "item_id", "model_type", "name"], ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], ) @@ -2129,6 +2326,8 @@ def create( unit_with_proration_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_allocation_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_with_prorated_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, + grouped_with_metered_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, + matrix_with_display_name_config: Dict[str, object] | NotGiven = NOT_GIVEN, bulk_with_proration_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -2179,6 +2378,8 @@ def create( "unit_with_proration_config": unit_with_proration_config, "grouped_allocation_config": grouped_allocation_config, "grouped_with_prorated_minimum_config": grouped_with_prorated_minimum_config, + "grouped_with_metered_minimum_config": grouped_with_metered_minimum_config, + "matrix_with_display_name_config": matrix_with_display_name_config, "bulk_with_proration_config": bulk_with_proration_config, "grouped_tiered_package_config": grouped_tiered_package_config, }, @@ -2433,10 +2634,21 @@ def external_price_id(self) -> AsyncExternalPriceID: @cached_property def with_raw_response(self) -> AsyncPricesWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncPricesWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncPricesWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncPricesWithStreamingResponse(self) @overload @@ -4249,6 +4461,190 @@ async def create( """ ... + @overload + async def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + grouped_with_metered_minimum_config: Dict[str, object], + item_id: str, + model_type: Literal["grouped_with_metered_minimum"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """This endpoint is used to create a [price](../reference/price). + + A price created + using this endpoint is always an add-on, meaning that it’s not associated with a + specific plan and can instead be individually added to subscriptions, including + subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](../reference/price) for the specification of different + price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + + @overload + async def create( + self, + *, + cadence: Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"], + currency: str, + item_id: str, + matrix_with_display_name_config: Dict[str, object], + model_type: Literal["matrix_with_display_name"], + name: str, + billable_metric_id: Optional[str] | NotGiven = NOT_GIVEN, + billed_in_advance: Optional[bool] | NotGiven = NOT_GIVEN, + billing_cycle_configuration: Optional[ + price_create_params.NewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + conversion_rate: Optional[float] | NotGiven = NOT_GIVEN, + external_price_id: Optional[str] | NotGiven = NOT_GIVEN, + fixed_price_quantity: Optional[float] | NotGiven = NOT_GIVEN, + invoice_grouping_key: Optional[str] | NotGiven = NOT_GIVEN, + invoicing_cycle_configuration: Optional[ + price_create_params.NewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration + ] + | NotGiven = NOT_GIVEN, + metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> Price: + """This endpoint is used to create a [price](../reference/price). + + A price created + using this endpoint is always an add-on, meaning that it’s not associated with a + specific plan and can instead be individually added to subscriptions, including + subscriptions on different plans. + + An `external_price_id` can be optionally specified as an alias to allow + ergonomic interaction with prices in the Orb API. + + See the [Price resource](../reference/price) for the specification of different + price model configurations possible in this endpoint. + + Args: + cadence: The cadence to bill for this price on. + + currency: An ISO 4217 currency string for which this price is billed in. + + item_id: The id of the item the plan will be associated with. + + name: The name of the price. + + billable_metric_id: The id of the billable metric for the price. Only needed if the price is + usage-based. + + billed_in_advance: If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + + billing_cycle_configuration: For custom cadence: specifies the duration of the billing period in days or + months. + + conversion_rate: The per unit conversion rate of the price currency to the invoicing currency. + + external_price_id: An alias for the price. + + fixed_price_quantity: If the Price represents a fixed cost, this represents the quantity of units + applied. + + invoice_grouping_key: The property used to group this price on an invoice + + invoicing_cycle_configuration: Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + + metadata: User-specified key/value pairs for the resource. Individual keys can be removed + by setting the value to `null`, and the entire metadata mapping can be cleared + by setting `metadata` to `null`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + ... + @overload async def create( self, @@ -4454,6 +4850,8 @@ async def create( ["cadence", "currency", "item_id", "model_type", "name", "unit_with_proration_config"], ["cadence", "currency", "grouped_allocation_config", "item_id", "model_type", "name"], ["cadence", "currency", "grouped_with_prorated_minimum_config", "item_id", "model_type", "name"], + ["cadence", "currency", "grouped_with_metered_minimum_config", "item_id", "model_type", "name"], + ["cadence", "currency", "item_id", "matrix_with_display_name_config", "model_type", "name"], ["bulk_with_proration_config", "cadence", "currency", "item_id", "model_type", "name"], ["cadence", "currency", "grouped_tiered_package_config", "item_id", "model_type", "name"], ) @@ -4520,6 +4918,8 @@ async def create( unit_with_proration_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_allocation_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_with_prorated_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, + grouped_with_metered_minimum_config: Dict[str, object] | NotGiven = NOT_GIVEN, + matrix_with_display_name_config: Dict[str, object] | NotGiven = NOT_GIVEN, bulk_with_proration_config: Dict[str, object] | NotGiven = NOT_GIVEN, grouped_tiered_package_config: Dict[str, object] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -4570,6 +4970,8 @@ async def create( "unit_with_proration_config": unit_with_proration_config, "grouped_allocation_config": grouped_allocation_config, "grouped_with_prorated_minimum_config": grouped_with_prorated_minimum_config, + "grouped_with_metered_minimum_config": grouped_with_metered_minimum_config, + "matrix_with_display_name_config": matrix_with_display_name_config, "bulk_with_proration_config": bulk_with_proration_config, "grouped_tiered_package_config": grouped_tiered_package_config, }, diff --git a/src/orb/resources/subscriptions.py b/src/orb/resources/subscriptions.py index 4155f2de..a377b5fa 100644 --- a/src/orb/resources/subscriptions.py +++ b/src/orb/resources/subscriptions.py @@ -16,6 +16,7 @@ subscription_update_params, subscription_fetch_costs_params, subscription_fetch_usage_params, + subscription_update_trial_params, subscription_trigger_phase_params, subscription_fetch_schedule_params, subscription_price_intervals_params, @@ -35,8 +36,22 @@ from .._base_client import AsyncPaginator, make_request_options from ..types.subscription import Subscription from ..types.subscription_usage import SubscriptionUsage +from ..types.subscription_cancel_response import SubscriptionCancelResponse +from ..types.subscription_create_response import SubscriptionCreateResponse from ..types.subscription_fetch_costs_response import SubscriptionFetchCostsResponse +from ..types.subscription_update_trial_response import SubscriptionUpdateTrialResponse +from ..types.subscription_trigger_phase_response import SubscriptionTriggerPhaseResponse from ..types.subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse +from ..types.subscription_price_intervals_response import SubscriptionPriceIntervalsResponse +from ..types.subscription_schedule_plan_change_response import SubscriptionSchedulePlanChangeResponse +from ..types.subscription_unschedule_cancellation_response import SubscriptionUnscheduleCancellationResponse +from ..types.subscription_update_fixed_fee_quantity_response import SubscriptionUpdateFixedFeeQuantityResponse +from ..types.subscription_unschedule_pending_plan_changes_response import ( + SubscriptionUnschedulePendingPlanChangesResponse, +) +from ..types.subscription_unschedule_fixed_fee_quantity_updates_response import ( + SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, +) __all__ = ["Subscriptions", "AsyncSubscriptions"] @@ -44,15 +59,28 @@ class Subscriptions(SyncAPIResource): @cached_property def with_raw_response(self) -> SubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return SubscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> SubscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return SubscriptionsWithStreamingResponse(self) def create( self, *, + add_adjustments: Optional[Iterable[subscription_create_params.AddAdjustment]] | NotGiven = NOT_GIVEN, + add_prices: Optional[Iterable[subscription_create_params.AddPrice]] | NotGiven = NOT_GIVEN, align_billing_with_subscription_start_date: bool | NotGiven = NOT_GIVEN, auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, aws_region: Optional[str] | NotGiven = NOT_GIVEN, @@ -67,14 +95,21 @@ def create( external_marketplace: Optional[Literal["google", "aws", "azure"]] | NotGiven = NOT_GIVEN, external_marketplace_reporting_id: Optional[str] | NotGiven = NOT_GIVEN, external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, + filter: Optional[str] | NotGiven = NOT_GIVEN, initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, net_terms: Optional[int] | NotGiven = NOT_GIVEN, per_credit_overage_amount: Optional[float] | NotGiven = NOT_GIVEN, plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_create_params.PriceOverride]] | NotGiven = NOT_GIVEN, + plan_version_number: Optional[int] | NotGiven = NOT_GIVEN, + price_overrides: Optional[Iterable[object]] | NotGiven = NOT_GIVEN, + remove_adjustments: Optional[Iterable[subscription_create_params.RemoveAdjustment]] | NotGiven = NOT_GIVEN, + remove_prices: Optional[Iterable[subscription_create_params.RemovePrice]] | NotGiven = NOT_GIVEN, + replace_adjustments: Optional[Iterable[subscription_create_params.ReplaceAdjustment]] | NotGiven = NOT_GIVEN, + replace_prices: Optional[Iterable[subscription_create_params.ReplacePrice]] | NotGiven = NOT_GIVEN, start_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + trial_duration_days: Optional[int] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -82,7 +117,7 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionCreateResponse: """A subscription represents the purchase of a plan by a customer. The customer is @@ -114,265 +149,130 @@ def create( not have a currency set, on subscription creation, we set the customer's currency to be the `invoicing_currency` of the plan. - ## Price overrides + ## Customize your customer's subscriptions - Price overrides are used to update some or all prices in a plan for the specific - subscription being created. This is useful when a new customer has negotiated - one or more different prices for a specific plan than the plan's default prices. - Any type of price can be overridden, if the correct data is provided. The - billable metric, cadence, type, and name of a price can not be overridden. + Prices and adjustments in a plan can be added, removed, or replaced for the + subscription being created. This is useful when a customer has prices that + differ from the default prices for a specific plan. - To override prices, provide a list of objects with the key `price_overrides`. - The price object in the list of overrides is expected to contain the existing - price id, the `model_type` and config value in the format below. The specific - numerical values can be updated, but the config value and `model_type` must - match the existing price that is being overridden + :::info This feature is only available for accounts that have migrated to + Subscription Overrides Version 2. You can find your Subscription Overrides + Version at the bottom of your [Plans page](https://app.withorb.com/plans) ::: - ### Request format for price overrides + ### Adding Prices - Orb supports a few different pricing models out of the box. The `model_type` - field determines the key for the configuration object that is present. + To add prices, provide a list of objects with the key `add_prices`. An object in + the list must specify an existing add-on price with a `price_id` or + `external_price_id` field, or create a new add-on price by including an object + with the key `price`, identical to what would be used in the request body for + the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. - ### Unit pricing + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the price should be added to. - With unit pricing, each unit costs a fixed amount. + An object in the list can specify an optional `start_date` and optional + `end_date`. This is equivalent to creating a price interval with the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). If + unspecified, the start or end date of the phase or subscription will be used. - ```json - { - ... - "id": "price_id", - "model_type": "unit", - "unit_config": { - "unit_amount": "0.50" - } - ... - } - ``` + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. - ### Tiered pricing + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference this price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. - In tiered pricing, the cost of a given unit depends on the tier range that it - falls into, where each tier range is defined by an upper and lower bound. For - example, the first ten units may cost $0.50 each and all units thereafter may - cost $0.10 each. Tiered prices can be overridden with a new number of tiers or - new values for `first_unit`, `last_unit`, or `unit_amount`. + ### Removing Prices - ```json - { - ... - "id": "price_id", - "model_type": "tiered", - "tiered_config": { - "tiers": [ - { - "first_unit":"1", - "last_unit": "10", - "unit_amount": "0.50" - }, - { - "first_unit": "10", - "last_unit": null, - "unit_amount": "0.10" - } - ] - } - ... - } - ``` + To remove prices, provide a list of objects with the key `remove_prices`. An + object in the list must specify a plan price with either a `price_id` or + `external_price_id` field. - ### Bulk pricing + ### Replacing Prices - Bulk pricing applies when the number of units determine the cost of _all_ units. - For example, if you've bought less than 10 units, they may each be $0.50 for a - total of $5.00. Once you've bought more than 10 units, all units may now be - priced at $0.40 (i.e. 101 units total would be $40.40). Bulk prices can be - overridden with a new number of tiers or new values for `maximum_units`, or - `unit_amount`. + To replace prices, provide a list of objects with the key `replace_prices`. An + object in the list must specify a plan price to replace with the + `replaces_price_id` key, and it must specify a price to replace it with by + either referencing an existing add-on price with a `price_id` or + `external_price_id` field, or by creating a new add-on price by including an + object with the key `price`, identical to what would be used in the request body + for the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. - ```json - { - ... - "id": "price_id", - "model_type": "bulk", - "bulk_config": { - "tiers": [ - { - "maximum_units": "10", - "unit_amount": "0.50" - }, - { - "maximum_units": "1000", - "unit_amount": "0.40" - } - ] - } - ... - } - ``` + For fixed fees, an object in the list can supply a `fixed_price_quantity` + instead of a `price`, `price_id`, or `external_price_id` field. This will update + only the quantity for the price, similar to the + [Update price quantity](../reference/update-fixed-fee-quantity) endpoint. - ### Package pricing + The replacement price will have the same phase, if applicable, and the same + start and end dates as the price it replaces. - Package pricing defines the size or granularity of a unit for billing purposes. - For example, if the package size is set to 5, then 4 units will be billed as 5 - and 6 units will be billed at 10. + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. - ```json - { - ... - "id": "price_id", - "model_type": "package", - "package_config": { - "package_amount": "0.80", - "package_size": 10 - } - ... - } - ``` + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference the replacement price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. - ### BPS pricing + ### Adding adjustments - BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a - percent (the number of basis points to charge), as well as a cap per event to - assess. For example, this would allow you to assess a fee of 0.25% on every - payment you process, with a maximum charge of $25 per payment. + To add adjustments, provide a list of objects with the key `add_adjustments`. An + object in the list must include an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). - ```json - { - ... - "id": "price_id" - "model_type": "bps", - "bps_config": { - "bps": 125, - "per_event_cap": "11.00" - } - ... - } - ``` + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the adjustment should be added + to. - ### Bulk BPS pricing + An object in the list can specify an optional `start_date` and optional + `end_date`. If unspecified, the start or end date of the phase or subscription + will be used. - Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the - total quantity across all events. Similar to bulk pricing, the BPS parameters of - a given event depends on the tier range that the billing period falls into. Each - tier range is defined by an upper and lower bound. For example, after $1.5M of - payment volume is reached, each individual payment may have a lower cap or a - smaller take-rate. + ### Removing adjustments - ```json - { - ... - "id": "price_id" - "model_type": "bulk_bps", - "bulk_bps_config": { - "tiers": [ - { - "minimum_amount": "0.00", - "maximum_amount": "1000000.00", - "bps": 125, - "per_event_cap": "19.00" - }, - { - "minimum_amount":"1000000.00", - "maximum_amount": null, - "bps": 115, - "per_event_cap": "4.00" - } - ] - } - ... - } - ``` + To remove adjustments, provide a list of objects with the key + `remove_adjustments`. An object in the list must include a key, `adjustment_id`, + with the ID of the adjustment to be removed. - ### Tiered BPS pricing + ### Replacing adjustments - Tiered BPS pricing specifies BPS parameters in a graduated manner, where an - event's applicable parameter is a function of its marginal addition to the - period total. Similar to tiered pricing, the BPS parameters of a given event - depends on the tier range that it falls into, where each tier range is defined - by an upper and lower bound. For example, the first few payments may have a 0.8 - BPS take-rate and all payments after a specific volume may incur a take-rate of - 0.5 BPS each. + To replace adjustments, provide a list of objects with the key + `replace_adjustments`. An object in the list must specify a plan adjustment to + replace with the `replaces_adjustment_id` key, and it must specify an adjustment + to replace it with by including an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). - ```json - { - ... - "id": "price_id" - "model_type": "tiered_bps", - "tiered_bps_config": { - "tiers": [ - { - "minimum_amount": "0.00", - "maximum_amount": "1000000.00", - "bps": 125, - "per_event_cap": "19.00" - }, - { - "minimum_amount":"1000000", - "maximum_amount": null, - "bps": 115, - "per_event_cap": "4.00" - } - ] - } - ... - } - ``` + The replacement adjustment will have the same phase, if applicable, and the same + start and end dates as the adjustment it replaces. - ### Matrix pricing + ## Price overrides (DEPRECATED) - Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. - `dimensions` defines the two event property values evaluated in this pricing - model. In a one-dimensional matrix, the second value is `null`. Every - configuration has a list of `matrix_values` which give the unit prices for - specified property values. In a one-dimensional matrix, the matrix values will - have `dimension_values` where the second value of the pair is null. If an event - does not match any of the dimension values in the matrix, it will resort to the - `default_unit_amount`. + :::info Price overrides are being phased out in favor adding/removing/replacing + prices. (See + [Customize your customer's subscriptions](../reference/create-subscription#customize-your-customers-subscriptions)) + ::: - ```json - { - ... - "model_type": "matrix", - "matrix_config": { - "default_unit_amount": "3.00", - "dimensions": [ - "cluster_name", - "region" - ], - "matrix_values": [ - { - "dimension_values": [ - "alpha", - "west" - ], - "unit_amount": "2.00" - }, - ... - ] - } - } - ``` - - ### Fixed fees - - Fixed fees follow unit pricing, and also have an additional parameter - `fixed_price_quantity` that indicates how many of a fixed fee that should be - applied for a subscription. This parameter defaults to 1. + Price overrides are used to update some or all prices in a plan for the specific + subscription being created. This is useful when a new customer has negotiated a + rate that is unique to the customer. - ```json - { - ... - "id": "price_id", - "model_type": "unit", - "unit_config": { - "unit_amount": "2.00" - }, - "fixed_price_quantity": 3.0 - ... - } - ``` + To override prices, provide a list of objects with the key `price_overrides`. + The price object in the list of overrides is expected to contain the existing + price id, the `model_type` and configuration. (See the + [Price resource](../reference/price) for the specification of different price + model configurations.) The numerical values can be updated, but the billable + metric, cadence, type, and name of a price can not be overridden. - ## Maximums and Minimums + ### Maximums and Minimums Minimums and maximums, much like price overrides, can be useful when a new customer has negotiated a new or different minimum or maximum spend cap than the @@ -419,13 +319,12 @@ def create( } ``` - ## Discounts + ### Discounts Discounts, like price overrides, can be useful when a new customer has - negotiated a new or different discount than the default for a price. A single - price price can have at most one discount. If a discount exists for a price and - a null discount is provided on creation, then there will be no discount on the - new subscription. + negotiated a new or different discount than the default for a price. If a + discount exists for a price and a null discount is provided on creation, then + there will be no discount on the new subscription. To add a discount for a specific price, add `discount` to the price in the `price_overrides` object. Discount should be a dictionary of the format: @@ -477,6 +376,12 @@ def create( $10.00 for a subscription that invoices in USD. Args: + add_adjustments: Additional adjustments to be added to the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + add_prices: Additional prices to be added to the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + auto_collection: Determines whether issued invoices for this subscription will automatically be charged with the saved payment method on the due date. If not specified, this defaults to the behavior configured for this customer. @@ -491,6 +396,11 @@ def create( external_plan_id: The external_plan_id of the plan that the given subscription should be switched to. Note that either this property or `plan_id` must be specified. + filter: An additional filter to apply to usage queries. This filter must be expressed as + a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + initial_phase_order: The phase of the plan to start with invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will @@ -508,8 +418,28 @@ def create( plan_id: The plan that the given subscription should be switched to. Note that either this property or `external_plan_id` must be specified. + plan_version_number: Specifies which version of the plan to subscribe to. If null, the default + version will be used. + price_overrides: Optionally provide a list of overrides for prices on the plan + remove_adjustments: Plan adjustments to be removed from the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + remove_prices: Plan prices to be removed from the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + + replace_adjustments: Plan adjustments to be replaced with additional adjustments on the subscription. + (Only available for accounts that have migrated off of legacy subscription + overrides) + + replace_prices: Plan prices to be replaced with additional prices on the subscription. (Only + available for accounts that have migrated off of legacy subscription overrides) + + trial_duration_days: The duration of the trial period in days. If not provided, this defaults to the + value specified in the plan. If `0` is provided, the trial on the plan will be + skipped. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -524,6 +454,8 @@ def create( "/subscriptions", body=maybe_transform( { + "add_adjustments": add_adjustments, + "add_prices": add_prices, "align_billing_with_subscription_start_date": align_billing_with_subscription_start_date, "auto_collection": auto_collection, "aws_region": aws_region, @@ -537,14 +469,21 @@ def create( "external_marketplace": external_marketplace, "external_marketplace_reporting_id": external_marketplace_reporting_id, "external_plan_id": external_plan_id, + "filter": filter, "initial_phase_order": initial_phase_order, "invoicing_threshold": invoicing_threshold, "metadata": metadata, "net_terms": net_terms, "per_credit_overage_amount": per_credit_overage_amount, "plan_id": plan_id, + "plan_version_number": plan_version_number, "price_overrides": price_overrides, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, "start_date": start_date, + "trial_duration_days": trial_duration_days, }, subscription_create_params.SubscriptionCreateParams, ), @@ -555,7 +494,7 @@ def create( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionCreateResponse, ) def update( @@ -718,7 +657,7 @@ def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionCancelResponse: """This endpoint can be used to cancel an existing subscription. It returns the @@ -817,7 +756,7 @@ def cancel( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionCancelResponse, ) def fetch( @@ -1275,7 +1214,7 @@ def price_intervals( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionPriceIntervalsResponse: """ This endpoint is used to add and edit subscription [price intervals](../reference/price-interval). By making modifications to a @@ -1389,7 +1328,7 @@ def price_intervals( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionPriceIntervalsResponse, ) def schedule_plan_change( @@ -1397,22 +1336,38 @@ def schedule_plan_change( subscription_id: str, *, change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], + add_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.AddAdjustment]] + | NotGiven = NOT_GIVEN, + add_prices: Optional[Iterable[subscription_schedule_plan_change_params.AddPrice]] | NotGiven = NOT_GIVEN, align_billing_with_plan_change_date: Optional[bool] | NotGiven = NOT_GIVEN, auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] | NotGiven = NOT_GIVEN, + billing_cycle_anchor_configuration: Optional[ + subscription_schedule_plan_change_params.BillingCycleAnchorConfiguration + ] + | NotGiven = NOT_GIVEN, change_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, + filter: Optional[str] | NotGiven = NOT_GIVEN, initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, net_terms: Optional[int] | NotGiven = NOT_GIVEN, per_credit_overage_amount: Optional[float] | NotGiven = NOT_GIVEN, plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_schedule_plan_change_params.PriceOverride]] + plan_version_number: Optional[int] | NotGiven = NOT_GIVEN, + price_overrides: Optional[Iterable[object]] | NotGiven = NOT_GIVEN, + remove_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.RemoveAdjustment]] + | NotGiven = NOT_GIVEN, + remove_prices: Optional[Iterable[subscription_schedule_plan_change_params.RemovePrice]] | NotGiven = NOT_GIVEN, + replace_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.ReplaceAdjustment]] | NotGiven = NOT_GIVEN, + replace_prices: Optional[Iterable[subscription_schedule_plan_change_params.ReplacePrice]] + | NotGiven = NOT_GIVEN, + trial_duration_days: Optional[int] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1420,41 +1375,177 @@ def schedule_plan_change( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: - """This endpoint can be used to change the plan on an existing subscription. + ) -> SubscriptionSchedulePlanChangeResponse: + """This endpoint can be used to change an existing subscription's plan. - It - returns the serialized updated subscription object. + It returns + the serialized updated subscription object. - The body parameter `change_option` determines the timing of the plan change. Orb + The body parameter `change_option` determines when the plan change occurrs. Orb supports three options: - `end_of_subscription_term`: changes the plan at the end of the existing plan's term. - Issuing this plan change request for a monthly subscription will keep the - existing plan active until the start of the subsequent month, and - potentially issue an invoice for any usage charges incurred in the - intervening period. - - Issuing this plan change request for a yearly subscription will keep the - existing plan active for the full year. - - `immediate`: changes the plan immediately. Subscriptions that have their plan - changed with this option will be invoiced immediately. This invoice will - include any usage fees incurred in the billing period up to the change, along - with any prorated recurring fees for the billing period, if applicable. - - `requested_date`: changes the plan on the requested date (`change_date`). If - no timezone is provided, the customer's timezone is used. The `change_date` - body parameter is required if this option is chosen. + existing plan active until the start of the subsequent month. Issuing this + plan change request for a yearly subscription will keep the existing plan + active for the full year. Charges incurred in the remaining period will be + invoiced as normal. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, so the plan will be changed on February 1st, and + invoice will be issued on February 1st for the last month of the original + plan. + - `immediate`: changes the plan immediately. + - Subscriptions that have their plan changed with this option will move to the + new plan immediately, and be invoiced immediately. + - This invoice will include any usage fees incurred in the billing period up + to the change, along with any prorated recurring fees for the billing + period, if applicable. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, so the plan will be changed on January 15th, and an + invoice will be issued for the partial month, from January 1 to January 15, + on the original plan. + - `requested_date`: changes the plan on the requested date (`change_date`). + - If no timezone is provided, the customer's timezone is used. The + `change_date` body parameter is required if this option is chosen. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, with a requested `change_date` of February 15th, so + the plan will be changed on February 15th, and invoices will be issued on + February 1st and February 15th. Note that one of `plan_id` or `external_plan_id` is required in the request body for this operation. - ## Price overrides, maximums, and minimums + ## Customize your customer's subscriptions + + Prices and adjustments in a plan can be added, removed, or replaced on the + subscription when you schedule the plan change. This is useful when a customer + has prices that differ from the default prices for a specific plan. + + :::info This feature is only available for accounts that have migrated to + Subscription Overrides Version 2. You can find your Subscription Overrides + Version at the bottom of your [Plans page](https://app.withorb.com/plans) ::: + + ### Adding Prices + + To add prices, provide a list of objects with the key `add_prices`. An object in + the list must specify an existing add-on price with a `price_id` or + `external_price_id` field, or create a new add-on price by including an object + with the key `price`, identical to what would be used in the request body for + the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. + + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the price should be added to. + + An object in the list can specify an optional `start_date` and optional + `end_date`. This is equivalent to creating a price interval with the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). If + unspecified, the start or end date of the phase or subscription will be used. + + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. + + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference this price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. + + ### Removing Prices + + To remove prices, provide a list of objects with the key `remove_prices`. An + object in the list must specify a plan price with either a `price_id` or + `external_price_id` field. + + ### Replacing Prices + + To replace prices, provide a list of objects with the key `replace_prices`. An + object in the list must specify a plan price to replace with the + `replaces_price_id` key, and it must specify a price to replace it with by + either referencing an existing add-on price with a `price_id` or + `external_price_id` field, or by creating a new add-on price by including an + object with the key `price`, identical to what would be used in the request body + for the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. + + For fixed fees, an object in the list can supply a `fixed_price_quantity` + instead of a `price`, `price_id`, or `external_price_id` field. This will update + only the quantity for the price, similar to the + [Update price quantity](../reference/update-fixed-fee-quantity) endpoint. + + The replacement price will have the same phase, if applicable, and the same + start and end dates as the price it replaces. + + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. + + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference the replacement price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. + + ### Adding adjustments + + To add adjustments, provide a list of objects with the key `add_adjustments`. An + object in the list must include an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). + + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the adjustment should be added + to. + + An object in the list can specify an optional `start_date` and optional + `end_date`. If unspecified, the start or end date of the phase or subscription + will be used. + + ### Removing adjustments + + To remove adjustments, provide a list of objects with the key + `remove_adjustments`. An object in the list must include a key, `adjustment_id`, + with the ID of the adjustment to be removed. + + ### Replacing adjustments + + To replace adjustments, provide a list of objects with the key + `replace_adjustments`. An object in the list must specify a plan adjustment to + replace with the `replaces_adjustment_id` key, and it must specify an adjustment + to replace it with by including an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). + + The replacement adjustment will have the same phase, if applicable, and the same + start and end dates as the adjustment it replaces. + + ## Price overrides (DEPRECATED) + + :::info Price overrides are being phased out in favor adding/removing/replacing + prices. (See + [Customize your customer's subscriptions](../reference/schedule-plan-change#customize-your-customers-subscriptions)) + ::: + + Price overrides are used to update some or all prices in a plan for the specific + subscription being created. This is useful when a new customer has negotiated a + rate that is unique to the customer. + + To override prices, provide a list of objects with the key `price_overrides`. + The price object in the list of overrides is expected to contain the existing + price id, the `model_type` and configuration. (See the + [Price resource](../reference/price) for the specification of different price + model configurations.) The numerical values can be updated, but the billable + metric, cadence, type, and name of a price can not be overridden. + + ### Maximums, and minimums Price overrides are used to update some or all prices in the target plan. Minimums and maximums, much like price overrides, can be useful when a new customer has negotiated a new or different minimum or maximum spend cap than the - default for the plan. The request format for price overrides, maximums, and - minimums are the same as those in [subscription creation](create-subscription). + default for the plan. The request format for maximums and minimums is the same + as those in [subscription creation](create-subscription). ## Scheduling multiple plan changes @@ -1469,6 +1560,12 @@ def schedule_plan_change( [Modifying subscriptions](../guides/product-catalog/modifying-subscriptions.md#prorations-for-in-advance-fees). Args: + add_adjustments: Additional adjustments to be added to the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + add_prices: Additional prices to be added to the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + align_billing_with_plan_change_date: [DEPRECATED] Use billing_cycle_alignment instead. Reset billing periods to be aligned with the plan change's effective date. @@ -1493,6 +1590,11 @@ def schedule_plan_change( external_plan_id: The external_plan_id of the plan that the given subscription should be switched to. Note that either this property or `plan_id` must be specified. + filter: An additional filter to apply to usage queries. This filter must be expressed as + a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + initial_phase_order: The phase of the plan to start with invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will @@ -1506,8 +1608,28 @@ def schedule_plan_change( plan_id: The plan that the given subscription should be switched to. Note that either this property or `external_plan_id` must be specified. + plan_version_number: Specifies which version of the plan to change to. If null, the default version + will be used. + price_overrides: Optionally provide a list of overrides for prices on the plan + remove_adjustments: Plan adjustments to be removed from the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + remove_prices: Plan prices to be removed from the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + + replace_adjustments: Plan adjustments to be replaced with additional adjustments on the subscription. + (Only available for accounts that have migrated off of legacy subscription + overrides) + + replace_prices: Plan prices to be replaced with additional prices on the subscription. (Only + available for accounts that have migrated off of legacy subscription overrides) + + trial_duration_days: The duration of the trial period in days. If not provided, this defaults to the + value specified in the plan. If `0` is provided, the trial on the plan will be + skipped. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1525,20 +1647,30 @@ def schedule_plan_change( body=maybe_transform( { "change_option": change_option, + "add_adjustments": add_adjustments, + "add_prices": add_prices, "align_billing_with_plan_change_date": align_billing_with_plan_change_date, "auto_collection": auto_collection, "billing_cycle_alignment": billing_cycle_alignment, + "billing_cycle_anchor_configuration": billing_cycle_anchor_configuration, "change_date": change_date, "coupon_redemption_code": coupon_redemption_code, "credits_overage_rate": credits_overage_rate, "default_invoice_memo": default_invoice_memo, "external_plan_id": external_plan_id, + "filter": filter, "initial_phase_order": initial_phase_order, "invoicing_threshold": invoicing_threshold, "net_terms": net_terms, "per_credit_overage_amount": per_credit_overage_amount, "plan_id": plan_id, + "plan_version_number": plan_version_number, "price_overrides": price_overrides, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "trial_duration_days": trial_duration_days, }, subscription_schedule_plan_change_params.SubscriptionSchedulePlanChangeParams, ), @@ -1549,7 +1681,7 @@ def schedule_plan_change( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionSchedulePlanChangeResponse, ) def trigger_phase( @@ -1564,7 +1696,7 @@ def trigger_phase( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionTriggerPhaseResponse: """ Manually trigger a phase, effective the given date (or the current time, if not specified). @@ -1597,7 +1729,7 @@ def trigger_phase( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionTriggerPhaseResponse, ) def unschedule_cancellation( @@ -1611,7 +1743,7 @@ def unschedule_cancellation( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnscheduleCancellationResponse: """ This endpoint can be used to unschedule any pending cancellations for a subscription. @@ -1642,7 +1774,7 @@ def unschedule_cancellation( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnscheduleCancellationResponse, ) def unschedule_fixed_fee_quantity_updates( @@ -1657,7 +1789,7 @@ def unschedule_fixed_fee_quantity_updates( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse: """ This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. @@ -1693,7 +1825,7 @@ def unschedule_fixed_fee_quantity_updates( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, ) def unschedule_pending_plan_changes( @@ -1707,7 +1839,7 @@ def unschedule_pending_plan_changes( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnschedulePendingPlanChangesResponse: """ This endpoint can be used to unschedule any pending plan changes on an existing subscription. @@ -1734,7 +1866,7 @@ def unschedule_pending_plan_changes( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnschedulePendingPlanChangesResponse, ) def update_fixed_fee_quantity( @@ -1752,7 +1884,7 @@ def update_fixed_fee_quantity( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUpdateFixedFeeQuantityResponse: """ This endpoint can be used to update the quantity for a fixed fee. @@ -1810,22 +1942,108 @@ def update_fixed_fee_quantity( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUpdateFixedFeeQuantityResponse, + ) + + def update_trial( + self, + subscription_id: str, + *, + trial_end_date: Union[Union[str, datetime], Literal["immediate"]], + shift: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> SubscriptionUpdateTrialResponse: + """This endpoint is used to update the trial end date for a subscription. + + The new + trial end date must be within the time range of the current plan (i.e. the new + trial end date must be on or after the subscription's start date on the current + plan, and on or before the subscription end date). + + In order to retroactively remove a trial completely, the end date can be set to + the transition date of the subscription to this plan (or, if this is the first + plan for this subscription, the subscription's start date). In order to end a + trial immediately, the keyword `immediate` can be provided as the trial end + date. + + By default, Orb will shift only the trial end date (and price intervals that + start or end on the previous trial end date), and leave all other future price + intervals untouched. If the `shift` parameter is set to `true`, Orb will shift + all subsequent price and adjustment intervals by the same amount as the trial + end date shift (so, e.g., if a plan change is scheduled or an add-on price was + added, that change will be pushed back by the same amount of time the trial is + extended). + + Args: + trial_end_date: The new date that the trial should end, or the literal string `immediate` to end + the trial immediately. + + shift: If true, shifts subsequent price and adjustment intervals (preserving their + durations, but adjusting their absolute dates). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + if not subscription_id: + raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") + return self._post( + f"/subscriptions/{subscription_id}/update_trial", + body=maybe_transform( + { + "trial_end_date": trial_end_date, + "shift": shift, + }, + subscription_update_trial_params.SubscriptionUpdateTrialParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionUpdateTrialResponse, ) class AsyncSubscriptions(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncSubscriptionsWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncSubscriptionsWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncSubscriptionsWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncSubscriptionsWithStreamingResponse(self) async def create( self, *, + add_adjustments: Optional[Iterable[subscription_create_params.AddAdjustment]] | NotGiven = NOT_GIVEN, + add_prices: Optional[Iterable[subscription_create_params.AddPrice]] | NotGiven = NOT_GIVEN, align_billing_with_subscription_start_date: bool | NotGiven = NOT_GIVEN, auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, aws_region: Optional[str] | NotGiven = NOT_GIVEN, @@ -1840,14 +2058,21 @@ async def create( external_marketplace: Optional[Literal["google", "aws", "azure"]] | NotGiven = NOT_GIVEN, external_marketplace_reporting_id: Optional[str] | NotGiven = NOT_GIVEN, external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, + filter: Optional[str] | NotGiven = NOT_GIVEN, initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, metadata: Optional[Dict[str, Optional[str]]] | NotGiven = NOT_GIVEN, net_terms: Optional[int] | NotGiven = NOT_GIVEN, per_credit_overage_amount: Optional[float] | NotGiven = NOT_GIVEN, plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_create_params.PriceOverride]] | NotGiven = NOT_GIVEN, + plan_version_number: Optional[int] | NotGiven = NOT_GIVEN, + price_overrides: Optional[Iterable[object]] | NotGiven = NOT_GIVEN, + remove_adjustments: Optional[Iterable[subscription_create_params.RemoveAdjustment]] | NotGiven = NOT_GIVEN, + remove_prices: Optional[Iterable[subscription_create_params.RemovePrice]] | NotGiven = NOT_GIVEN, + replace_adjustments: Optional[Iterable[subscription_create_params.ReplaceAdjustment]] | NotGiven = NOT_GIVEN, + replace_prices: Optional[Iterable[subscription_create_params.ReplacePrice]] | NotGiven = NOT_GIVEN, start_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, + trial_duration_days: Optional[int] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1855,7 +2080,7 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionCreateResponse: """A subscription represents the purchase of a plan by a customer. The customer is @@ -1887,265 +2112,130 @@ async def create( not have a currency set, on subscription creation, we set the customer's currency to be the `invoicing_currency` of the plan. - ## Price overrides + ## Customize your customer's subscriptions - Price overrides are used to update some or all prices in a plan for the specific - subscription being created. This is useful when a new customer has negotiated - one or more different prices for a specific plan than the plan's default prices. - Any type of price can be overridden, if the correct data is provided. The - billable metric, cadence, type, and name of a price can not be overridden. + Prices and adjustments in a plan can be added, removed, or replaced for the + subscription being created. This is useful when a customer has prices that + differ from the default prices for a specific plan. - To override prices, provide a list of objects with the key `price_overrides`. - The price object in the list of overrides is expected to contain the existing - price id, the `model_type` and config value in the format below. The specific - numerical values can be updated, but the config value and `model_type` must - match the existing price that is being overridden + :::info This feature is only available for accounts that have migrated to + Subscription Overrides Version 2. You can find your Subscription Overrides + Version at the bottom of your [Plans page](https://app.withorb.com/plans) ::: - ### Request format for price overrides + ### Adding Prices - Orb supports a few different pricing models out of the box. The `model_type` - field determines the key for the configuration object that is present. + To add prices, provide a list of objects with the key `add_prices`. An object in + the list must specify an existing add-on price with a `price_id` or + `external_price_id` field, or create a new add-on price by including an object + with the key `price`, identical to what would be used in the request body for + the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. - ### Unit pricing + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the price should be added to. - With unit pricing, each unit costs a fixed amount. + An object in the list can specify an optional `start_date` and optional + `end_date`. This is equivalent to creating a price interval with the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). If + unspecified, the start or end date of the phase or subscription will be used. - ```json - { - ... - "id": "price_id", - "model_type": "unit", - "unit_config": { - "unit_amount": "0.50" - } - ... - } - ``` + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. - ### Tiered pricing + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference this price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. - In tiered pricing, the cost of a given unit depends on the tier range that it - falls into, where each tier range is defined by an upper and lower bound. For - example, the first ten units may cost $0.50 each and all units thereafter may - cost $0.10 each. Tiered prices can be overridden with a new number of tiers or - new values for `first_unit`, `last_unit`, or `unit_amount`. + ### Removing Prices - ```json - { - ... - "id": "price_id", - "model_type": "tiered", - "tiered_config": { - "tiers": [ - { - "first_unit":"1", - "last_unit": "10", - "unit_amount": "0.50" - }, - { - "first_unit": "10", - "last_unit": null, - "unit_amount": "0.10" - } - ] - } - ... - } - ``` + To remove prices, provide a list of objects with the key `remove_prices`. An + object in the list must specify a plan price with either a `price_id` or + `external_price_id` field. - ### Bulk pricing + ### Replacing Prices - Bulk pricing applies when the number of units determine the cost of _all_ units. - For example, if you've bought less than 10 units, they may each be $0.50 for a - total of $5.00. Once you've bought more than 10 units, all units may now be - priced at $0.40 (i.e. 101 units total would be $40.40). Bulk prices can be - overridden with a new number of tiers or new values for `maximum_units`, or - `unit_amount`. + To replace prices, provide a list of objects with the key `replace_prices`. An + object in the list must specify a plan price to replace with the + `replaces_price_id` key, and it must specify a price to replace it with by + either referencing an existing add-on price with a `price_id` or + `external_price_id` field, or by creating a new add-on price by including an + object with the key `price`, identical to what would be used in the request body + for the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. - ```json - { - ... - "id": "price_id", - "model_type": "bulk", - "bulk_config": { - "tiers": [ - { - "maximum_units": "10", - "unit_amount": "0.50" - }, - { - "maximum_units": "1000", - "unit_amount": "0.40" - } - ] - } - ... - } - ``` + For fixed fees, an object in the list can supply a `fixed_price_quantity` + instead of a `price`, `price_id`, or `external_price_id` field. This will update + only the quantity for the price, similar to the + [Update price quantity](../reference/update-fixed-fee-quantity) endpoint. - ### Package pricing + The replacement price will have the same phase, if applicable, and the same + start and end dates as the price it replaces. - Package pricing defines the size or granularity of a unit for billing purposes. - For example, if the package size is set to 5, then 4 units will be billed as 5 - and 6 units will be billed at 10. + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. - ```json - { - ... - "id": "price_id", - "model_type": "package", - "package_config": { - "package_amount": "0.80", - "package_size": 10 - } - ... - } - ``` + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference the replacement price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. - ### BPS pricing + ### Adding adjustments - BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a - percent (the number of basis points to charge), as well as a cap per event to - assess. For example, this would allow you to assess a fee of 0.25% on every - payment you process, with a maximum charge of $25 per payment. + To add adjustments, provide a list of objects with the key `add_adjustments`. An + object in the list must include an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). - ```json - { - ... - "id": "price_id" - "model_type": "bps", - "bps_config": { - "bps": 125, - "per_event_cap": "11.00" - } - ... - } - ``` + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the adjustment should be added + to. - ### Bulk BPS pricing + An object in the list can specify an optional `start_date` and optional + `end_date`. If unspecified, the start or end date of the phase or subscription + will be used. - Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the - total quantity across all events. Similar to bulk pricing, the BPS parameters of - a given event depends on the tier range that the billing period falls into. Each - tier range is defined by an upper and lower bound. For example, after $1.5M of - payment volume is reached, each individual payment may have a lower cap or a - smaller take-rate. + ### Removing adjustments - ```json - { - ... - "id": "price_id" - "model_type": "bulk_bps", - "bulk_bps_config": { - "tiers": [ - { - "minimum_amount": "0.00", - "maximum_amount": "1000000.00", - "bps": 125, - "per_event_cap": "19.00" - }, - { - "minimum_amount":"1000000.00", - "maximum_amount": null, - "bps": 115, - "per_event_cap": "4.00" - } - ] - } - ... - } - ``` + To remove adjustments, provide a list of objects with the key + `remove_adjustments`. An object in the list must include a key, `adjustment_id`, + with the ID of the adjustment to be removed. - ### Tiered BPS pricing + ### Replacing adjustments - Tiered BPS pricing specifies BPS parameters in a graduated manner, where an - event's applicable parameter is a function of its marginal addition to the - period total. Similar to tiered pricing, the BPS parameters of a given event - depends on the tier range that it falls into, where each tier range is defined - by an upper and lower bound. For example, the first few payments may have a 0.8 - BPS take-rate and all payments after a specific volume may incur a take-rate of - 0.5 BPS each. + To replace adjustments, provide a list of objects with the key + `replace_adjustments`. An object in the list must specify a plan adjustment to + replace with the `replaces_adjustment_id` key, and it must specify an adjustment + to replace it with by including an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). - ```json - { - ... - "id": "price_id" - "model_type": "tiered_bps", - "tiered_bps_config": { - "tiers": [ - { - "minimum_amount": "0.00", - "maximum_amount": "1000000.00", - "bps": 125, - "per_event_cap": "19.00" - }, - { - "minimum_amount":"1000000", - "maximum_amount": null, - "bps": 115, - "per_event_cap": "4.00" - } - ] - } - ... - } - ``` + The replacement adjustment will have the same phase, if applicable, and the same + start and end dates as the adjustment it replaces. - ### Matrix pricing + ## Price overrides (DEPRECATED) - Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. - `dimensions` defines the two event property values evaluated in this pricing - model. In a one-dimensional matrix, the second value is `null`. Every - configuration has a list of `matrix_values` which give the unit prices for - specified property values. In a one-dimensional matrix, the matrix values will - have `dimension_values` where the second value of the pair is null. If an event - does not match any of the dimension values in the matrix, it will resort to the - `default_unit_amount`. + :::info Price overrides are being phased out in favor adding/removing/replacing + prices. (See + [Customize your customer's subscriptions](../reference/create-subscription#customize-your-customers-subscriptions)) + ::: - ```json - { - ... - "model_type": "matrix", - "matrix_config": { - "default_unit_amount": "3.00", - "dimensions": [ - "cluster_name", - "region" - ], - "matrix_values": [ - { - "dimension_values": [ - "alpha", - "west" - ], - "unit_amount": "2.00" - }, - ... - ] - } - } - ``` - - ### Fixed fees - - Fixed fees follow unit pricing, and also have an additional parameter - `fixed_price_quantity` that indicates how many of a fixed fee that should be - applied for a subscription. This parameter defaults to 1. + Price overrides are used to update some or all prices in a plan for the specific + subscription being created. This is useful when a new customer has negotiated a + rate that is unique to the customer. - ```json - { - ... - "id": "price_id", - "model_type": "unit", - "unit_config": { - "unit_amount": "2.00" - }, - "fixed_price_quantity": 3.0 - ... - } - ``` + To override prices, provide a list of objects with the key `price_overrides`. + The price object in the list of overrides is expected to contain the existing + price id, the `model_type` and configuration. (See the + [Price resource](../reference/price) for the specification of different price + model configurations.) The numerical values can be updated, but the billable + metric, cadence, type, and name of a price can not be overridden. - ## Maximums and Minimums + ### Maximums and Minimums Minimums and maximums, much like price overrides, can be useful when a new customer has negotiated a new or different minimum or maximum spend cap than the @@ -2192,13 +2282,12 @@ async def create( } ``` - ## Discounts + ### Discounts Discounts, like price overrides, can be useful when a new customer has - negotiated a new or different discount than the default for a price. A single - price price can have at most one discount. If a discount exists for a price and - a null discount is provided on creation, then there will be no discount on the - new subscription. + negotiated a new or different discount than the default for a price. If a + discount exists for a price and a null discount is provided on creation, then + there will be no discount on the new subscription. To add a discount for a specific price, add `discount` to the price in the `price_overrides` object. Discount should be a dictionary of the format: @@ -2250,6 +2339,12 @@ async def create( $10.00 for a subscription that invoices in USD. Args: + add_adjustments: Additional adjustments to be added to the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + add_prices: Additional prices to be added to the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + auto_collection: Determines whether issued invoices for this subscription will automatically be charged with the saved payment method on the due date. If not specified, this defaults to the behavior configured for this customer. @@ -2264,6 +2359,11 @@ async def create( external_plan_id: The external_plan_id of the plan that the given subscription should be switched to. Note that either this property or `plan_id` must be specified. + filter: An additional filter to apply to usage queries. This filter must be expressed as + a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + initial_phase_order: The phase of the plan to start with invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will @@ -2281,8 +2381,28 @@ async def create( plan_id: The plan that the given subscription should be switched to. Note that either this property or `external_plan_id` must be specified. + plan_version_number: Specifies which version of the plan to subscribe to. If null, the default + version will be used. + price_overrides: Optionally provide a list of overrides for prices on the plan + remove_adjustments: Plan adjustments to be removed from the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + remove_prices: Plan prices to be removed from the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + + replace_adjustments: Plan adjustments to be replaced with additional adjustments on the subscription. + (Only available for accounts that have migrated off of legacy subscription + overrides) + + replace_prices: Plan prices to be replaced with additional prices on the subscription. (Only + available for accounts that have migrated off of legacy subscription overrides) + + trial_duration_days: The duration of the trial period in days. If not provided, this defaults to the + value specified in the plan. If `0` is provided, the trial on the plan will be + skipped. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -2297,6 +2417,8 @@ async def create( "/subscriptions", body=await async_maybe_transform( { + "add_adjustments": add_adjustments, + "add_prices": add_prices, "align_billing_with_subscription_start_date": align_billing_with_subscription_start_date, "auto_collection": auto_collection, "aws_region": aws_region, @@ -2310,14 +2432,21 @@ async def create( "external_marketplace": external_marketplace, "external_marketplace_reporting_id": external_marketplace_reporting_id, "external_plan_id": external_plan_id, + "filter": filter, "initial_phase_order": initial_phase_order, "invoicing_threshold": invoicing_threshold, "metadata": metadata, "net_terms": net_terms, "per_credit_overage_amount": per_credit_overage_amount, "plan_id": plan_id, + "plan_version_number": plan_version_number, "price_overrides": price_overrides, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, "start_date": start_date, + "trial_duration_days": trial_duration_days, }, subscription_create_params.SubscriptionCreateParams, ), @@ -2328,7 +2457,7 @@ async def create( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionCreateResponse, ) async def update( @@ -2491,7 +2620,7 @@ async def cancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionCancelResponse: """This endpoint can be used to cancel an existing subscription. It returns the @@ -2590,7 +2719,7 @@ async def cancel( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionCancelResponse, ) async def fetch( @@ -3048,7 +3177,7 @@ async def price_intervals( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionPriceIntervalsResponse: """ This endpoint is used to add and edit subscription [price intervals](../reference/price-interval). By making modifications to a @@ -3162,7 +3291,7 @@ async def price_intervals( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionPriceIntervalsResponse, ) async def schedule_plan_change( @@ -3170,22 +3299,38 @@ async def schedule_plan_change( subscription_id: str, *, change_option: Literal["requested_date", "end_of_subscription_term", "immediate"], + add_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.AddAdjustment]] + | NotGiven = NOT_GIVEN, + add_prices: Optional[Iterable[subscription_schedule_plan_change_params.AddPrice]] | NotGiven = NOT_GIVEN, align_billing_with_plan_change_date: Optional[bool] | NotGiven = NOT_GIVEN, auto_collection: Optional[bool] | NotGiven = NOT_GIVEN, billing_cycle_alignment: Optional[Literal["unchanged", "plan_change_date", "start_of_month"]] | NotGiven = NOT_GIVEN, + billing_cycle_anchor_configuration: Optional[ + subscription_schedule_plan_change_params.BillingCycleAnchorConfiguration + ] + | NotGiven = NOT_GIVEN, change_date: Union[str, datetime, None] | NotGiven = NOT_GIVEN, coupon_redemption_code: Optional[str] | NotGiven = NOT_GIVEN, credits_overage_rate: Optional[float] | NotGiven = NOT_GIVEN, default_invoice_memo: Optional[str] | NotGiven = NOT_GIVEN, external_plan_id: Optional[str] | NotGiven = NOT_GIVEN, + filter: Optional[str] | NotGiven = NOT_GIVEN, initial_phase_order: Optional[int] | NotGiven = NOT_GIVEN, invoicing_threshold: Optional[str] | NotGiven = NOT_GIVEN, net_terms: Optional[int] | NotGiven = NOT_GIVEN, per_credit_overage_amount: Optional[float] | NotGiven = NOT_GIVEN, plan_id: Optional[str] | NotGiven = NOT_GIVEN, - price_overrides: Optional[Iterable[subscription_schedule_plan_change_params.PriceOverride]] + plan_version_number: Optional[int] | NotGiven = NOT_GIVEN, + price_overrides: Optional[Iterable[object]] | NotGiven = NOT_GIVEN, + remove_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.RemoveAdjustment]] + | NotGiven = NOT_GIVEN, + remove_prices: Optional[Iterable[subscription_schedule_plan_change_params.RemovePrice]] | NotGiven = NOT_GIVEN, + replace_adjustments: Optional[Iterable[subscription_schedule_plan_change_params.ReplaceAdjustment]] + | NotGiven = NOT_GIVEN, + replace_prices: Optional[Iterable[subscription_schedule_plan_change_params.ReplacePrice]] | NotGiven = NOT_GIVEN, + trial_duration_days: Optional[int] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -3193,41 +3338,177 @@ async def schedule_plan_change( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: - """This endpoint can be used to change the plan on an existing subscription. + ) -> SubscriptionSchedulePlanChangeResponse: + """This endpoint can be used to change an existing subscription's plan. - It - returns the serialized updated subscription object. + It returns + the serialized updated subscription object. - The body parameter `change_option` determines the timing of the plan change. Orb + The body parameter `change_option` determines when the plan change occurrs. Orb supports three options: - `end_of_subscription_term`: changes the plan at the end of the existing plan's term. - Issuing this plan change request for a monthly subscription will keep the - existing plan active until the start of the subsequent month, and - potentially issue an invoice for any usage charges incurred in the - intervening period. - - Issuing this plan change request for a yearly subscription will keep the - existing plan active for the full year. - - `immediate`: changes the plan immediately. Subscriptions that have their plan - changed with this option will be invoiced immediately. This invoice will - include any usage fees incurred in the billing period up to the change, along - with any prorated recurring fees for the billing period, if applicable. - - `requested_date`: changes the plan on the requested date (`change_date`). If - no timezone is provided, the customer's timezone is used. The `change_date` - body parameter is required if this option is chosen. + existing plan active until the start of the subsequent month. Issuing this + plan change request for a yearly subscription will keep the existing plan + active for the full year. Charges incurred in the remaining period will be + invoiced as normal. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, so the plan will be changed on February 1st, and + invoice will be issued on February 1st for the last month of the original + plan. + - `immediate`: changes the plan immediately. + - Subscriptions that have their plan changed with this option will move to the + new plan immediately, and be invoiced immediately. + - This invoice will include any usage fees incurred in the billing period up + to the change, along with any prorated recurring fees for the billing + period, if applicable. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, so the plan will be changed on January 15th, and an + invoice will be issued for the partial month, from January 1 to January 15, + on the original plan. + - `requested_date`: changes the plan on the requested date (`change_date`). + - If no timezone is provided, the customer's timezone is used. The + `change_date` body parameter is required if this option is chosen. + - Example: The plan is billed monthly on the 1st of the month, the request is + made on January 15th, with a requested `change_date` of February 15th, so + the plan will be changed on February 15th, and invoices will be issued on + February 1st and February 15th. Note that one of `plan_id` or `external_plan_id` is required in the request body for this operation. - ## Price overrides, maximums, and minimums + ## Customize your customer's subscriptions + + Prices and adjustments in a plan can be added, removed, or replaced on the + subscription when you schedule the plan change. This is useful when a customer + has prices that differ from the default prices for a specific plan. + + :::info This feature is only available for accounts that have migrated to + Subscription Overrides Version 2. You can find your Subscription Overrides + Version at the bottom of your [Plans page](https://app.withorb.com/plans) ::: + + ### Adding Prices + + To add prices, provide a list of objects with the key `add_prices`. An object in + the list must specify an existing add-on price with a `price_id` or + `external_price_id` field, or create a new add-on price by including an object + with the key `price`, identical to what would be used in the request body for + the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. + + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the price should be added to. + + An object in the list can specify an optional `start_date` and optional + `end_date`. This is equivalent to creating a price interval with the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). If + unspecified, the start or end date of the phase or subscription will be used. + + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. + + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference this price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. + + ### Removing Prices + + To remove prices, provide a list of objects with the key `remove_prices`. An + object in the list must specify a plan price with either a `price_id` or + `external_price_id` field. + + ### Replacing Prices + + To replace prices, provide a list of objects with the key `replace_prices`. An + object in the list must specify a plan price to replace with the + `replaces_price_id` key, and it must specify a price to replace it with by + either referencing an existing add-on price with a `price_id` or + `external_price_id` field, or by creating a new add-on price by including an + object with the key `price`, identical to what would be used in the request body + for the [create price endpoint](../reference/create-price). See the + [Price resource](../reference/price) for the specification of different price + model configurations possible in this object. + + For fixed fees, an object in the list can supply a `fixed_price_quantity` + instead of a `price`, `price_id`, or `external_price_id` field. This will update + only the quantity for the price, similar to the + [Update price quantity](../reference/update-fixed-fee-quantity) endpoint. + + The replacement price will have the same phase, if applicable, and the same + start and end dates as the price it replaces. + + An object in the list can specify an optional `minimum_amount`, + `maximum_amount`, or `discounts`. This will create adjustments which apply only + to this price. + + Additionally, an object in the list can specify an optional `reference_id`. This + ID can be used to reference the replacement price when + [adding an adjustment](#adding-adjustments) in the same API call. However the ID + is _transient_ and cannot be used to refer to the price in future API calls. + + ### Adding adjustments + + To add adjustments, provide a list of objects with the key `add_adjustments`. An + object in the list must include an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). + + If the plan has phases, each object in the list must include a number with + `plan_phase_order` key to indicate which phase the adjustment should be added + to. + + An object in the list can specify an optional `start_date` and optional + `end_date`. If unspecified, the start or end date of the phase or subscription + will be used. + + ### Removing adjustments + + To remove adjustments, provide a list of objects with the key + `remove_adjustments`. An object in the list must include a key, `adjustment_id`, + with the ID of the adjustment to be removed. + + ### Replacing adjustments + + To replace adjustments, provide a list of objects with the key + `replace_adjustments`. An object in the list must specify a plan adjustment to + replace with the `replaces_adjustment_id` key, and it must specify an adjustment + to replace it with by including an object with the key `adjustment`, identical + to the adjustment object in the + [add/edit price intervals endpoint](../reference/add-edit-price-intervals). + + The replacement adjustment will have the same phase, if applicable, and the same + start and end dates as the adjustment it replaces. + + ## Price overrides (DEPRECATED) + + :::info Price overrides are being phased out in favor adding/removing/replacing + prices. (See + [Customize your customer's subscriptions](../reference/schedule-plan-change#customize-your-customers-subscriptions)) + ::: + + Price overrides are used to update some or all prices in a plan for the specific + subscription being created. This is useful when a new customer has negotiated a + rate that is unique to the customer. + + To override prices, provide a list of objects with the key `price_overrides`. + The price object in the list of overrides is expected to contain the existing + price id, the `model_type` and configuration. (See the + [Price resource](../reference/price) for the specification of different price + model configurations.) The numerical values can be updated, but the billable + metric, cadence, type, and name of a price can not be overridden. + + ### Maximums, and minimums Price overrides are used to update some or all prices in the target plan. Minimums and maximums, much like price overrides, can be useful when a new customer has negotiated a new or different minimum or maximum spend cap than the - default for the plan. The request format for price overrides, maximums, and - minimums are the same as those in [subscription creation](create-subscription). + default for the plan. The request format for maximums and minimums is the same + as those in [subscription creation](create-subscription). ## Scheduling multiple plan changes @@ -3242,6 +3523,12 @@ async def schedule_plan_change( [Modifying subscriptions](../guides/product-catalog/modifying-subscriptions.md#prorations-for-in-advance-fees). Args: + add_adjustments: Additional adjustments to be added to the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + add_prices: Additional prices to be added to the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + align_billing_with_plan_change_date: [DEPRECATED] Use billing_cycle_alignment instead. Reset billing periods to be aligned with the plan change's effective date. @@ -3266,6 +3553,11 @@ async def schedule_plan_change( external_plan_id: The external_plan_id of the plan that the given subscription should be switched to. Note that either this property or `plan_id` must be specified. + filter: An additional filter to apply to usage queries. This filter must be expressed as + a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + initial_phase_order: The phase of the plan to start with invoicing_threshold: When this subscription's accrued usage reaches this threshold, an invoice will @@ -3279,8 +3571,28 @@ async def schedule_plan_change( plan_id: The plan that the given subscription should be switched to. Note that either this property or `external_plan_id` must be specified. + plan_version_number: Specifies which version of the plan to change to. If null, the default version + will be used. + price_overrides: Optionally provide a list of overrides for prices on the plan + remove_adjustments: Plan adjustments to be removed from the subscription. (Only available for + accounts that have migrated off of legacy subscription overrides) + + remove_prices: Plan prices to be removed from the subscription. (Only available for accounts + that have migrated off of legacy subscription overrides) + + replace_adjustments: Plan adjustments to be replaced with additional adjustments on the subscription. + (Only available for accounts that have migrated off of legacy subscription + overrides) + + replace_prices: Plan prices to be replaced with additional prices on the subscription. (Only + available for accounts that have migrated off of legacy subscription overrides) + + trial_duration_days: The duration of the trial period in days. If not provided, this defaults to the + value specified in the plan. If `0` is provided, the trial on the plan will be + skipped. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -3298,20 +3610,30 @@ async def schedule_plan_change( body=await async_maybe_transform( { "change_option": change_option, + "add_adjustments": add_adjustments, + "add_prices": add_prices, "align_billing_with_plan_change_date": align_billing_with_plan_change_date, "auto_collection": auto_collection, "billing_cycle_alignment": billing_cycle_alignment, + "billing_cycle_anchor_configuration": billing_cycle_anchor_configuration, "change_date": change_date, "coupon_redemption_code": coupon_redemption_code, "credits_overage_rate": credits_overage_rate, "default_invoice_memo": default_invoice_memo, "external_plan_id": external_plan_id, + "filter": filter, "initial_phase_order": initial_phase_order, "invoicing_threshold": invoicing_threshold, "net_terms": net_terms, "per_credit_overage_amount": per_credit_overage_amount, "plan_id": plan_id, + "plan_version_number": plan_version_number, "price_overrides": price_overrides, + "remove_adjustments": remove_adjustments, + "remove_prices": remove_prices, + "replace_adjustments": replace_adjustments, + "replace_prices": replace_prices, + "trial_duration_days": trial_duration_days, }, subscription_schedule_plan_change_params.SubscriptionSchedulePlanChangeParams, ), @@ -3322,7 +3644,7 @@ async def schedule_plan_change( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionSchedulePlanChangeResponse, ) async def trigger_phase( @@ -3337,7 +3659,7 @@ async def trigger_phase( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionTriggerPhaseResponse: """ Manually trigger a phase, effective the given date (or the current time, if not specified). @@ -3370,7 +3692,7 @@ async def trigger_phase( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionTriggerPhaseResponse, ) async def unschedule_cancellation( @@ -3384,7 +3706,7 @@ async def unschedule_cancellation( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnscheduleCancellationResponse: """ This endpoint can be used to unschedule any pending cancellations for a subscription. @@ -3415,7 +3737,7 @@ async def unschedule_cancellation( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnscheduleCancellationResponse, ) async def unschedule_fixed_fee_quantity_updates( @@ -3430,7 +3752,7 @@ async def unschedule_fixed_fee_quantity_updates( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse: """ This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. @@ -3466,7 +3788,7 @@ async def unschedule_fixed_fee_quantity_updates( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, ) async def unschedule_pending_plan_changes( @@ -3480,7 +3802,7 @@ async def unschedule_pending_plan_changes( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUnschedulePendingPlanChangesResponse: """ This endpoint can be used to unschedule any pending plan changes on an existing subscription. @@ -3507,7 +3829,7 @@ async def unschedule_pending_plan_changes( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUnschedulePendingPlanChangesResponse, ) async def update_fixed_fee_quantity( @@ -3525,7 +3847,7 @@ async def update_fixed_fee_quantity( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, - ) -> Subscription: + ) -> SubscriptionUpdateFixedFeeQuantityResponse: """ This endpoint can be used to update the quantity for a fixed fee. @@ -3583,7 +3905,80 @@ async def update_fixed_fee_quantity( timeout=timeout, idempotency_key=idempotency_key, ), - cast_to=Subscription, + cast_to=SubscriptionUpdateFixedFeeQuantityResponse, + ) + + async def update_trial( + self, + subscription_id: str, + *, + trial_end_date: Union[Union[str, datetime], Literal["immediate"]], + shift: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + idempotency_key: str | None = None, + ) -> SubscriptionUpdateTrialResponse: + """This endpoint is used to update the trial end date for a subscription. + + The new + trial end date must be within the time range of the current plan (i.e. the new + trial end date must be on or after the subscription's start date on the current + plan, and on or before the subscription end date). + + In order to retroactively remove a trial completely, the end date can be set to + the transition date of the subscription to this plan (or, if this is the first + plan for this subscription, the subscription's start date). In order to end a + trial immediately, the keyword `immediate` can be provided as the trial end + date. + + By default, Orb will shift only the trial end date (and price intervals that + start or end on the previous trial end date), and leave all other future price + intervals untouched. If the `shift` parameter is set to `true`, Orb will shift + all subsequent price and adjustment intervals by the same amount as the trial + end date shift (so, e.g., if a plan change is scheduled or an add-on price was + added, that change will be pushed back by the same amount of time the trial is + extended). + + Args: + trial_end_date: The new date that the trial should end, or the literal string `immediate` to end + the trial immediately. + + shift: If true, shifts subsequent price and adjustment intervals (preserving their + durations, but adjusting their absolute dates). + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + + idempotency_key: Specify a custom idempotency key for this request + """ + if not subscription_id: + raise ValueError(f"Expected a non-empty value for `subscription_id` but received {subscription_id!r}") + return await self._post( + f"/subscriptions/{subscription_id}/update_trial", + body=await async_maybe_transform( + { + "trial_end_date": trial_end_date, + "shift": shift, + }, + subscription_update_trial_params.SubscriptionUpdateTrialParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=SubscriptionUpdateTrialResponse, ) @@ -3636,6 +4031,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.update_fixed_fee_quantity = _legacy_response.to_raw_response_wrapper( subscriptions.update_fixed_fee_quantity, ) + self.update_trial = _legacy_response.to_raw_response_wrapper( + subscriptions.update_trial, + ) class AsyncSubscriptionsWithRawResponse: @@ -3687,6 +4085,9 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.update_fixed_fee_quantity = _legacy_response.async_to_raw_response_wrapper( subscriptions.update_fixed_fee_quantity, ) + self.update_trial = _legacy_response.async_to_raw_response_wrapper( + subscriptions.update_trial, + ) class SubscriptionsWithStreamingResponse: @@ -3738,6 +4139,9 @@ def __init__(self, subscriptions: Subscriptions) -> None: self.update_fixed_fee_quantity = to_streamed_response_wrapper( subscriptions.update_fixed_fee_quantity, ) + self.update_trial = to_streamed_response_wrapper( + subscriptions.update_trial, + ) class AsyncSubscriptionsWithStreamingResponse: @@ -3789,3 +4193,6 @@ def __init__(self, subscriptions: AsyncSubscriptions) -> None: self.update_fixed_fee_quantity = async_to_streamed_response_wrapper( subscriptions.update_fixed_fee_quantity, ) + self.update_trial = async_to_streamed_response_wrapper( + subscriptions.update_trial, + ) diff --git a/src/orb/resources/top_level.py b/src/orb/resources/top_level.py index 4968a63a..032d08d4 100644 --- a/src/orb/resources/top_level.py +++ b/src/orb/resources/top_level.py @@ -18,10 +18,21 @@ class TopLevel(SyncAPIResource): @cached_property def with_raw_response(self) -> TopLevelWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return TopLevelWithRawResponse(self) @cached_property def with_streaming_response(self) -> TopLevelWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return TopLevelWithStreamingResponse(self) def ping( @@ -54,10 +65,21 @@ def ping( class AsyncTopLevel(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncTopLevelWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/orbcorp/orb-python#accessing-raw-response-data-eg-headers + """ return AsyncTopLevelWithRawResponse(self) @cached_property def with_streaming_response(self) -> AsyncTopLevelWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/orbcorp/orb-python#with_streaming_response + """ return AsyncTopLevelWithStreamingResponse(self) async def ping( diff --git a/src/orb/types/__init__.py b/src/orb/types/__init__.py index 3c43ed44..bbccb109 100644 --- a/src/orb/types/__init__.py +++ b/src/orb/types/__init__.py @@ -9,7 +9,11 @@ from .coupon import Coupon as Coupon from .shared import ( Discount as Discount, + TrialDiscount as TrialDiscount, + AmountDiscount as AmountDiscount, PaginationMetadata as PaginationMetadata, + PercentageDiscount as PercentageDiscount, + InvoiceLevelDiscount as InvoiceLevelDiscount, BillingCycleRelativeDate as BillingCycleRelativeDate, ) from .invoice import Invoice as Invoice @@ -39,6 +43,7 @@ from .coupon_create_params import CouponCreateParams as CouponCreateParams from .customer_list_params import CustomerListParams as CustomerListParams from .evaluate_price_group import EvaluatePriceGroup as EvaluatePriceGroup +from .invoice_issue_params import InvoiceIssueParams as InvoiceIssueParams from .metric_create_params import MetricCreateParams as MetricCreateParams from .metric_update_params import MetricUpdateParams as MetricUpdateParams from .event_ingest_response import EventIngestResponse as EventIngestResponse @@ -55,32 +60,56 @@ from .event_deprecate_response import EventDeprecateResponse as EventDeprecateResponse from .invoice_mark_paid_params import InvoiceMarkPaidParams as InvoiceMarkPaidParams from .subscription_list_params import SubscriptionListParams as SubscriptionListParams +from .credit_note_create_params import CreditNoteCreateParams as CreditNoteCreateParams from .subscription_cancel_params import SubscriptionCancelParams as SubscriptionCancelParams from .subscription_create_params import SubscriptionCreateParams as SubscriptionCreateParams from .subscription_update_params import SubscriptionUpdateParams as SubscriptionUpdateParams +from .subscription_cancel_response import SubscriptionCancelResponse as SubscriptionCancelResponse +from .subscription_create_response import SubscriptionCreateResponse as SubscriptionCreateResponse from .invoice_fetch_upcoming_params import InvoiceFetchUpcomingParams as InvoiceFetchUpcomingParams from .invoice_fetch_upcoming_response import InvoiceFetchUpcomingResponse as InvoiceFetchUpcomingResponse from .invoice_line_item_create_params import InvoiceLineItemCreateParams as InvoiceLineItemCreateParams from .subscription_fetch_costs_params import SubscriptionFetchCostsParams as SubscriptionFetchCostsParams from .subscription_fetch_usage_params import SubscriptionFetchUsageParams as SubscriptionFetchUsageParams from .alert_create_for_customer_params import AlertCreateForCustomerParams as AlertCreateForCustomerParams +from .subscription_update_trial_params import SubscriptionUpdateTrialParams as SubscriptionUpdateTrialParams from .invoice_line_item_create_response import InvoiceLineItemCreateResponse as InvoiceLineItemCreateResponse from .subscription_fetch_costs_response import SubscriptionFetchCostsResponse as SubscriptionFetchCostsResponse from .subscription_trigger_phase_params import SubscriptionTriggerPhaseParams as SubscriptionTriggerPhaseParams from .subscription_fetch_schedule_params import SubscriptionFetchScheduleParams as SubscriptionFetchScheduleParams +from .subscription_update_trial_response import SubscriptionUpdateTrialResponse as SubscriptionUpdateTrialResponse from .subscription_price_intervals_params import SubscriptionPriceIntervalsParams as SubscriptionPriceIntervalsParams +from .subscription_trigger_phase_response import SubscriptionTriggerPhaseResponse as SubscriptionTriggerPhaseResponse from .alert_create_for_subscription_params import AlertCreateForSubscriptionParams as AlertCreateForSubscriptionParams from .subscription_fetch_schedule_response import SubscriptionFetchScheduleResponse as SubscriptionFetchScheduleResponse from .customer_update_by_external_id_params import CustomerUpdateByExternalIDParams as CustomerUpdateByExternalIDParams +from .subscription_price_intervals_response import ( + SubscriptionPriceIntervalsResponse as SubscriptionPriceIntervalsResponse, +) from .subscription_schedule_plan_change_params import ( SubscriptionSchedulePlanChangeParams as SubscriptionSchedulePlanChangeParams, ) from .alert_create_for_external_customer_params import ( AlertCreateForExternalCustomerParams as AlertCreateForExternalCustomerParams, ) +from .subscription_schedule_plan_change_response import ( + SubscriptionSchedulePlanChangeResponse as SubscriptionSchedulePlanChangeResponse, +) +from .subscription_unschedule_cancellation_response import ( + SubscriptionUnscheduleCancellationResponse as SubscriptionUnscheduleCancellationResponse, +) from .subscription_update_fixed_fee_quantity_params import ( SubscriptionUpdateFixedFeeQuantityParams as SubscriptionUpdateFixedFeeQuantityParams, ) +from .subscription_update_fixed_fee_quantity_response import ( + SubscriptionUpdateFixedFeeQuantityResponse as SubscriptionUpdateFixedFeeQuantityResponse, +) +from .subscription_unschedule_pending_plan_changes_response import ( + SubscriptionUnschedulePendingPlanChangesResponse as SubscriptionUnschedulePendingPlanChangesResponse, +) from .subscription_unschedule_fixed_fee_quantity_updates_params import ( SubscriptionUnscheduleFixedFeeQuantityUpdatesParams as SubscriptionUnscheduleFixedFeeQuantityUpdatesParams, ) +from .subscription_unschedule_fixed_fee_quantity_updates_response import ( + SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse as SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, +) diff --git a/src/orb/types/coupon.py b/src/orb/types/coupon.py index 5003327d..c0ac61bd 100644 --- a/src/orb/types/coupon.py +++ b/src/orb/types/coupon.py @@ -1,51 +1,17 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional +from typing import Union, Optional from datetime import datetime -from typing_extensions import Literal, Annotated, TypeAlias +from typing_extensions import Annotated, TypeAlias from .._utils import PropertyInfo from .._models import BaseModel +from .shared.amount_discount import AmountDiscount +from .shared.percentage_discount import PercentageDiscount -__all__ = ["Coupon", "Discount", "DiscountPercentageDiscount", "DiscountAmountDiscount"] +__all__ = ["Coupon", "Discount"] - -class DiscountPercentageDiscount(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Literal["percentage"] - - percentage_discount: float - """Only available if discount_type is `percentage`. - - This is a number between 0 and 1. - """ - - reason: Optional[str] = None - - -class DiscountAmountDiscount(BaseModel): - amount_discount: str - """Only available if discount_type is `amount`.""" - - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Literal["amount"] - - reason: Optional[str] = None - - -Discount: TypeAlias = Annotated[ - Union[DiscountPercentageDiscount, DiscountAmountDiscount], PropertyInfo(discriminator="discount_type") -] +Discount: TypeAlias = Annotated[Union[PercentageDiscount, AmountDiscount], PropertyInfo(discriminator="discount_type")] class Coupon(BaseModel): diff --git a/src/orb/types/credit_note_create_params.py b/src/orb/types/credit_note_create_params.py new file mode 100644 index 00000000..ded73543 --- /dev/null +++ b/src/orb/types/credit_note_create_params.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["CreditNoteCreateParams", "LineItem"] + + +class CreditNoteCreateParams(TypedDict, total=False): + line_items: Required[Iterable[LineItem]] + + memo: Optional[str] + """An optional memo to attach to the credit note.""" + + reason: Optional[Literal["duplicate", "fraudulent", "order_change", "product_unsatisfactory"]] + """An optional reason for the credit note.""" + + +class LineItem(TypedDict, total=False): + amount: Required[str] + """The total amount in the invoice's currency to credit this line item.""" + + invoice_line_item_id: Required[str] + """The ID of the line item to credit.""" diff --git a/src/orb/types/customer.py b/src/orb/types/customer.py index 679a29a4..5b4bd50a 100644 --- a/src/orb/types/customer.py +++ b/src/orb/types/customer.py @@ -245,6 +245,8 @@ class Customer(BaseModel): email_delivery: bool + exempt_from_automated_tax: Optional[bool] = None + external_customer_id: Optional[str] = None """ An optional user-defined ID for this customer resource, used throughout the diff --git a/src/orb/types/customer_create_params.py b/src/orb/types/customer_create_params.py index 24f380f9..625a3534 100644 --- a/src/orb/types/customer_create_params.py +++ b/src/orb/types/customer_create_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = [ "CustomerCreateParams", @@ -12,6 +12,9 @@ "BillingAddress", "ReportingConfiguration", "ShippingAddress", + "TaxConfiguration", + "TaxConfigurationNewAvalaraTaxConfiguration", + "TaxConfigurationNewTaxJarConfiguration", "TaxID", ] @@ -83,6 +86,8 @@ class CustomerCreateParams(TypedDict, total=False): shipping_address: Optional[ShippingAddress] + tax_configuration: Optional[TaxConfiguration] + tax_id: Optional[TaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are @@ -244,6 +249,23 @@ class ShippingAddress(TypedDict, total=False): state: Optional[str] +class TaxConfigurationNewAvalaraTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["avalara"]] + + tax_exemption_code: Optional[str] + + +class TaxConfigurationNewTaxJarConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["taxjar"]] + + +TaxConfiguration: TypeAlias = Union[TaxConfigurationNewAvalaraTaxConfiguration, TaxConfigurationNewTaxJarConfiguration] + + class TaxID(TypedDict, total=False): country: Required[ Literal[ diff --git a/src/orb/types/customer_update_by_external_id_params.py b/src/orb/types/customer_update_by_external_id_params.py index 66f25cb3..a4b86160 100644 --- a/src/orb/types/customer_update_by_external_id_params.py +++ b/src/orb/types/customer_update_by_external_id_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = [ "CustomerUpdateByExternalIDParams", @@ -12,6 +12,9 @@ "BillingAddress", "ReportingConfiguration", "ShippingAddress", + "TaxConfiguration", + "TaxConfigurationNewAvalaraTaxConfiguration", + "TaxConfigurationNewTaxJarConfiguration", "TaxID", ] @@ -83,6 +86,8 @@ class CustomerUpdateByExternalIDParams(TypedDict, total=False): shipping_address: Optional[ShippingAddress] + tax_configuration: Optional[TaxConfiguration] + tax_id: Optional[TaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are @@ -237,6 +242,23 @@ class ShippingAddress(TypedDict, total=False): state: Optional[str] +class TaxConfigurationNewAvalaraTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["avalara"]] + + tax_exemption_code: Optional[str] + + +class TaxConfigurationNewTaxJarConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["taxjar"]] + + +TaxConfiguration: TypeAlias = Union[TaxConfigurationNewAvalaraTaxConfiguration, TaxConfigurationNewTaxJarConfiguration] + + class TaxID(TypedDict, total=False): country: Required[ Literal[ diff --git a/src/orb/types/customer_update_params.py b/src/orb/types/customer_update_params.py index b36781be..93e9021e 100644 --- a/src/orb/types/customer_update_params.py +++ b/src/orb/types/customer_update_params.py @@ -2,8 +2,8 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional -from typing_extensions import Literal, Required, TypedDict +from typing import Dict, List, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict __all__ = [ "CustomerUpdateParams", @@ -12,6 +12,9 @@ "BillingAddress", "ReportingConfiguration", "ShippingAddress", + "TaxConfiguration", + "TaxConfigurationNewAvalaraTaxConfiguration", + "TaxConfigurationNewTaxJarConfiguration", "TaxID", ] @@ -83,6 +86,8 @@ class CustomerUpdateParams(TypedDict, total=False): shipping_address: Optional[ShippingAddress] + tax_configuration: Optional[TaxConfiguration] + tax_id: Optional[TaxID] """ Tax IDs are commonly required to be displayed on customer invoices, which are @@ -237,6 +242,23 @@ class ShippingAddress(TypedDict, total=False): state: Optional[str] +class TaxConfigurationNewAvalaraTaxConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["avalara"]] + + tax_exemption_code: Optional[str] + + +class TaxConfigurationNewTaxJarConfiguration(TypedDict, total=False): + tax_exempt: Required[bool] + + tax_provider: Required[Literal["taxjar"]] + + +TaxConfiguration: TypeAlias = Union[TaxConfigurationNewAvalaraTaxConfiguration, TaxConfigurationNewTaxJarConfiguration] + + class TaxID(TypedDict, total=False): country: Required[ Literal[ diff --git a/src/orb/types/customers/credits/ledger_create_entry_by_external_id_response.py b/src/orb/types/customers/credits/ledger_create_entry_by_external_id_response.py index 82acb578..903d95f3 100644 --- a/src/orb/types/customers/credits/ledger_create_entry_by_external_id_response.py +++ b/src/orb/types/customers/credits/ledger_create_entry_by_external_id_response.py @@ -180,7 +180,7 @@ class ExpirationChangeLedgerEntry(BaseModel): cleared by setting `metadata` to `null`. """ - new_block_expiry_date: datetime + new_block_expiry_date: Optional[datetime] = None starting_balance: float diff --git a/src/orb/types/customers/credits/ledger_create_entry_response.py b/src/orb/types/customers/credits/ledger_create_entry_response.py index 17dc5228..f21c2562 100644 --- a/src/orb/types/customers/credits/ledger_create_entry_response.py +++ b/src/orb/types/customers/credits/ledger_create_entry_response.py @@ -180,7 +180,7 @@ class ExpirationChangeLedgerEntry(BaseModel): cleared by setting `metadata` to `null`. """ - new_block_expiry_date: datetime + new_block_expiry_date: Optional[datetime] = None starting_balance: float diff --git a/src/orb/types/customers/credits/ledger_list_by_external_id_response.py b/src/orb/types/customers/credits/ledger_list_by_external_id_response.py index fd5d03a2..e7b515fd 100644 --- a/src/orb/types/customers/credits/ledger_list_by_external_id_response.py +++ b/src/orb/types/customers/credits/ledger_list_by_external_id_response.py @@ -180,7 +180,7 @@ class ExpirationChangeLedgerEntry(BaseModel): cleared by setting `metadata` to `null`. """ - new_block_expiry_date: datetime + new_block_expiry_date: Optional[datetime] = None starting_balance: float diff --git a/src/orb/types/customers/credits/ledger_list_response.py b/src/orb/types/customers/credits/ledger_list_response.py index c02858de..26008bcc 100644 --- a/src/orb/types/customers/credits/ledger_list_response.py +++ b/src/orb/types/customers/credits/ledger_list_response.py @@ -180,7 +180,7 @@ class ExpirationChangeLedgerEntry(BaseModel): cleared by setting `metadata` to `null`. """ - new_block_expiry_date: datetime + new_block_expiry_date: Optional[datetime] = None starting_balance: float diff --git a/src/orb/types/event_deprecate_response.py b/src/orb/types/event_deprecate_response.py index 08b4aecb..1ef11446 100644 --- a/src/orb/types/event_deprecate_response.py +++ b/src/orb/types/event_deprecate_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["EventDeprecateResponse"] diff --git a/src/orb/types/event_update_response.py b/src/orb/types/event_update_response.py index aa91fd81..5c79e769 100644 --- a/src/orb/types/event_update_response.py +++ b/src/orb/types/event_update_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["EventUpdateResponse"] diff --git a/src/orb/types/events/__init__.py b/src/orb/types/events/__init__.py index a13aa150..554bf2a0 100644 --- a/src/orb/types/events/__init__.py +++ b/src/orb/types/events/__init__.py @@ -2,6 +2,8 @@ from __future__ import annotations +from .event_volumes import EventVolumes as EventVolumes +from .volume_list_params import VolumeListParams as VolumeListParams from .backfill_list_params import BackfillListParams as BackfillListParams from .backfill_create_params import BackfillCreateParams as BackfillCreateParams from .backfill_list_response import BackfillListResponse as BackfillListResponse diff --git a/src/orb/types/events/backfill_close_response.py b/src/orb/types/events/backfill_close_response.py index 393fc793..1252f588 100644 --- a/src/orb/types/events/backfill_close_response.py +++ b/src/orb/types/events/backfill_close_response.py @@ -21,9 +21,9 @@ class BackfillCloseResponse(BaseModel): created_at: datetime customer_id: Optional[str] = None - """The customer ID this backfill is scoped to. + """The Orb-generated ID of the customer to which this backfill is scoped. - If null, this backfill is not scoped to a single customer. + If `null`, this backfill is scoped to all customers. """ events_ingested: int diff --git a/src/orb/types/events/backfill_create_params.py b/src/orb/types/events/backfill_create_params.py index 1c526f39..2a8a90dd 100644 --- a/src/orb/types/events/backfill_create_params.py +++ b/src/orb/types/events/backfill_create_params.py @@ -27,7 +27,10 @@ class BackfillCreateParams(TypedDict, total=False): """ customer_id: Optional[str] - """The ID of the customer to which this backfill is scoped.""" + """The Orb-generated ID of the customer to which this backfill is scoped. + + Omitting this field will scope the backfill to all customers. + """ deprecation_filter: Optional[str] """ @@ -37,7 +40,10 @@ class BackfillCreateParams(TypedDict, total=False): """ external_customer_id: Optional[str] - """The external customer ID of the customer to which this backfill is scoped.""" + """The external customer ID of the customer to which this backfill is scoped. + + Omitting this field will scope the backfill to all customers. + """ replace_existing_events: bool """ diff --git a/src/orb/types/events/backfill_create_response.py b/src/orb/types/events/backfill_create_response.py index d8b9f837..1ef4b0f2 100644 --- a/src/orb/types/events/backfill_create_response.py +++ b/src/orb/types/events/backfill_create_response.py @@ -21,9 +21,9 @@ class BackfillCreateResponse(BaseModel): created_at: datetime customer_id: Optional[str] = None - """The customer ID this backfill is scoped to. + """The Orb-generated ID of the customer to which this backfill is scoped. - If null, this backfill is not scoped to a single customer. + If `null`, this backfill is scoped to all customers. """ events_ingested: int diff --git a/src/orb/types/events/backfill_fetch_response.py b/src/orb/types/events/backfill_fetch_response.py index c82d950b..3a772e64 100644 --- a/src/orb/types/events/backfill_fetch_response.py +++ b/src/orb/types/events/backfill_fetch_response.py @@ -21,9 +21,9 @@ class BackfillFetchResponse(BaseModel): created_at: datetime customer_id: Optional[str] = None - """The customer ID this backfill is scoped to. + """The Orb-generated ID of the customer to which this backfill is scoped. - If null, this backfill is not scoped to a single customer. + If `null`, this backfill is scoped to all customers. """ events_ingested: int diff --git a/src/orb/types/events/backfill_list_response.py b/src/orb/types/events/backfill_list_response.py index 2df11980..f2bfc632 100644 --- a/src/orb/types/events/backfill_list_response.py +++ b/src/orb/types/events/backfill_list_response.py @@ -21,9 +21,9 @@ class BackfillListResponse(BaseModel): created_at: datetime customer_id: Optional[str] = None - """The customer ID this backfill is scoped to. + """The Orb-generated ID of the customer to which this backfill is scoped. - If null, this backfill is not scoped to a single customer. + If `null`, this backfill is scoped to all customers. """ events_ingested: int diff --git a/src/orb/types/events/backfill_revert_response.py b/src/orb/types/events/backfill_revert_response.py index 39ad6836..c65b6ee9 100644 --- a/src/orb/types/events/backfill_revert_response.py +++ b/src/orb/types/events/backfill_revert_response.py @@ -21,9 +21,9 @@ class BackfillRevertResponse(BaseModel): created_at: datetime customer_id: Optional[str] = None - """The customer ID this backfill is scoped to. + """The Orb-generated ID of the customer to which this backfill is scoped. - If null, this backfill is not scoped to a single customer. + If `null`, this backfill is scoped to all customers. """ events_ingested: int diff --git a/src/orb/types/events/event_volumes.py b/src/orb/types/events/event_volumes.py new file mode 100644 index 00000000..f9852aac --- /dev/null +++ b/src/orb/types/events/event_volumes.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["EventVolumes", "Data"] + + +class Data(BaseModel): + count: int + """The number of events ingested with a timestamp between the timeframe""" + + timeframe_end: datetime + + timeframe_start: datetime + + +class EventVolumes(BaseModel): + data: List[Data] diff --git a/src/orb/types/events/volume_list_params.py b/src/orb/types/events/volume_list_params.py new file mode 100644 index 00000000..3a38b234 --- /dev/null +++ b/src/orb/types/events/volume_list_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["VolumeListParams"] + + +class VolumeListParams(TypedDict, total=False): + timeframe_start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] + """The start of the timeframe, inclusive, in which to return event volume. + + All datetime values are converted to UTC time. If the specified time isn't + hour-aligned, the response includes the event volume count for the hour the time + falls in. + """ + + cursor: Optional[str] + """Cursor for pagination. + + This can be populated by the `next_cursor` value returned from the initial + request. + """ + + limit: int + """The number of items to fetch. Defaults to 20.""" + + timeframe_end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """The end of the timeframe, exclusive, in which to return event volume. + + If not specified, the current time is used. All datetime values are converted to + UTC time.If the specified time isn't hour-aligned, the response includes the + event volumecount for the hour the time falls in. + """ diff --git a/src/orb/types/invoice.py b/src/orb/types/invoice.py index 4019c548..964e0f7d 100644 --- a/src/orb/types/invoice.py +++ b/src/orb/types/invoice.py @@ -8,6 +8,7 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.discount import Discount +from .shared.invoice_level_discount import InvoiceLevelDiscount __all__ = [ "Invoice", @@ -917,9 +918,14 @@ class Invoice(BaseModel): | Vietnam | `vn_tin` | Vietnamese Tax ID Number | """ - discount: Optional[Discount] = None + discount: Optional[object] = None + """This field is deprecated in favor of `discounts`. + + If a `discounts` list is provided, the first discount in the list will be + returned. If the list is empty, `None` will be returned. + """ - discounts: List[Discount] + discounts: List[InvoiceLevelDiscount] due_date: datetime """When the invoice payment is due.""" @@ -932,7 +938,11 @@ class Invoice(BaseModel): """ hosted_invoice_url: Optional[str] = None - """A URL for the invoice portal.""" + """A URL for the customer-facing invoice portal. + + This URL expires 30 days after the invoice's due date, or 60 days after being + re-generated through the UI. + """ invoice_date: datetime """The scheduled date of the invoice""" diff --git a/src/orb/types/invoice_fetch_upcoming_params.py b/src/orb/types/invoice_fetch_upcoming_params.py index 0d219ef7..6c81cde6 100644 --- a/src/orb/types/invoice_fetch_upcoming_params.py +++ b/src/orb/types/invoice_fetch_upcoming_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing_extensions import Required, TypedDict __all__ = ["InvoiceFetchUpcomingParams"] class InvoiceFetchUpcomingParams(TypedDict, total=False): - subscription_id: str + subscription_id: Required[str] diff --git a/src/orb/types/invoice_fetch_upcoming_response.py b/src/orb/types/invoice_fetch_upcoming_response.py index f59a6eda..8ec2e987 100644 --- a/src/orb/types/invoice_fetch_upcoming_response.py +++ b/src/orb/types/invoice_fetch_upcoming_response.py @@ -8,6 +8,7 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.discount import Discount +from .shared.invoice_level_discount import InvoiceLevelDiscount __all__ = [ "InvoiceFetchUpcomingResponse", @@ -917,9 +918,14 @@ class InvoiceFetchUpcomingResponse(BaseModel): | Vietnam | `vn_tin` | Vietnamese Tax ID Number | """ - discount: Optional[Discount] = None + discount: Optional[object] = None + """This field is deprecated in favor of `discounts`. + + If a `discounts` list is provided, the first discount in the list will be + returned. If the list is empty, `None` will be returned. + """ - discounts: List[Discount] + discounts: List[InvoiceLevelDiscount] due_date: datetime """When the invoice payment is due.""" @@ -932,7 +938,11 @@ class InvoiceFetchUpcomingResponse(BaseModel): """ hosted_invoice_url: Optional[str] = None - """A URL for the invoice portal.""" + """A URL for the customer-facing invoice portal. + + This URL expires 30 days after the invoice's due date, or 60 days after being + re-generated through the UI. + """ invoice_number: str """Automatically generated invoice number to help track and reconcile invoices. diff --git a/src/orb/types/invoice_issue_params.py b/src/orb/types/invoice_issue_params.py new file mode 100644 index 00000000..986b1667 --- /dev/null +++ b/src/orb/types/invoice_issue_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["InvoiceIssueParams"] + + +class InvoiceIssueParams(TypedDict, total=False): + synchronous: bool + """If true, the invoice will be issued synchronously. + + If false, the invoice will be issued asynchronously. The synchronous option is + only available for invoices containin no usage fees. If the invoice is + configured to sync to an external provider, a successful response from this + endpoint guarantees the invoice is present in the provider. + """ diff --git a/src/orb/types/plan.py b/src/orb/types/plan.py index f3b3b805..1f72a913 100644 --- a/src/orb/types/plan.py +++ b/src/orb/types/plan.py @@ -1,15 +1,22 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, List, Optional +from typing import Dict, List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, Annotated, TypeAlias from .price import Price +from .._utils import PropertyInfo from .._models import BaseModel from .shared.discount import Discount __all__ = [ "Plan", + "Adjustment", + "AdjustmentAmountDiscountAdjustment", + "AdjustmentPercentageDiscountAdjustment", + "AdjustmentUsageDiscountAdjustment", + "AdjustmentMinimumAdjustment", + "AdjustmentMaximumAdjustment", "BasePlan", "Maximum", "Minimum", @@ -21,6 +28,156 @@ ] +class AdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +Adjustment: TypeAlias = Annotated[ + Union[ + AdjustmentAmountDiscountAdjustment, + AdjustmentPercentageDiscountAdjustment, + AdjustmentUsageDiscountAdjustment, + AdjustmentMinimumAdjustment, + AdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + class BasePlan(BaseModel): id: Optional[str] = None @@ -124,6 +281,12 @@ class TrialConfig(BaseModel): class Plan(BaseModel): id: str + adjustments: List[Adjustment] + """Adjustments for this plan. + + If the plan has phases, this includes adjustments across all phases of the plan. + """ + base_plan: Optional[BasePlan] = None base_plan_id: Optional[str] = None diff --git a/src/orb/types/plan_create_params.py b/src/orb/types/plan_create_params.py index d84af11a..9c4e0060 100644 --- a/src/orb/types/plan_create_params.py +++ b/src/orb/types/plan_create_params.py @@ -72,6 +72,12 @@ "PriceNewPlanGroupedWithProratedMinimumPrice", "PriceNewPlanGroupedWithProratedMinimumPriceBillingCycleConfiguration", "PriceNewPlanGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "PriceNewPlanGroupedWithMeteredMinimumPrice", + "PriceNewPlanGroupedWithMeteredMinimumPriceBillingCycleConfiguration", + "PriceNewPlanGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration", + "PriceNewPlanMatrixWithDisplayNamePrice", + "PriceNewPlanMatrixWithDisplayNamePriceBillingCycleConfiguration", + "PriceNewPlanMatrixWithDisplayNamePriceInvoicingCycleConfiguration", "PriceNewPlanBulkWithProrationPrice", "PriceNewPlanBulkWithProrationPriceBillingCycleConfiguration", "PriceNewPlanBulkWithProrationPriceInvoicingCycleConfiguration", @@ -1653,6 +1659,172 @@ class PriceNewPlanGroupedWithProratedMinimumPrice(TypedDict, total=False): """ +class PriceNewPlanGroupedWithMeteredMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanGroupedWithMeteredMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_metered_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[PriceNewPlanGroupedWithMeteredMinimumPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[PriceNewPlanGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + +class PriceNewPlanMatrixWithDisplayNamePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanMatrixWithDisplayNamePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class PriceNewPlanMatrixWithDisplayNamePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + matrix_with_display_name_config: Required[Dict[str, object]] + + model_type: Required[Literal["matrix_with_display_name"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[PriceNewPlanMatrixWithDisplayNamePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[PriceNewPlanMatrixWithDisplayNamePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + class PriceNewPlanBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): duration: Required[int] """The duration of the billing period.""" @@ -1837,6 +2009,8 @@ class PriceNewPlanGroupedTieredPackagePrice(TypedDict, total=False): PriceNewPlanUnitWithProrationPrice, PriceNewPlanGroupedAllocationPrice, PriceNewPlanGroupedWithProratedMinimumPrice, + PriceNewPlanGroupedWithMeteredMinimumPrice, + PriceNewPlanMatrixWithDisplayNamePrice, PriceNewPlanBulkWithProrationPrice, PriceNewPlanGroupedTieredPackagePrice, ] diff --git a/src/orb/types/price.py b/src/orb/types/price.py index dcce7864..3273da59 100644 --- a/src/orb/types/price.py +++ b/src/orb/types/price.py @@ -187,6 +187,22 @@ "GroupedWithProratedMinimumPriceItem", "GroupedWithProratedMinimumPriceMaximum", "GroupedWithProratedMinimumPriceMinimum", + "GroupedWithMeteredMinimumPrice", + "GroupedWithMeteredMinimumPriceBillableMetric", + "GroupedWithMeteredMinimumPriceBillingCycleConfiguration", + "GroupedWithMeteredMinimumPriceCreditAllocation", + "GroupedWithMeteredMinimumPriceInvoicingCycleConfiguration", + "GroupedWithMeteredMinimumPriceItem", + "GroupedWithMeteredMinimumPriceMaximum", + "GroupedWithMeteredMinimumPriceMinimum", + "MatrixWithDisplayNamePrice", + "MatrixWithDisplayNamePriceBillableMetric", + "MatrixWithDisplayNamePriceBillingCycleConfiguration", + "MatrixWithDisplayNamePriceCreditAllocation", + "MatrixWithDisplayNamePriceInvoicingCycleConfiguration", + "MatrixWithDisplayNamePriceItem", + "MatrixWithDisplayNamePriceMaximum", + "MatrixWithDisplayNamePriceMinimum", "BulkWithProrationPrice", "BulkWithProrationPriceBillableMetric", "BulkWithProrationPriceBillingCycleConfiguration", @@ -2430,6 +2446,214 @@ class GroupedWithProratedMinimumPrice(BaseModel): price_type: Literal["usage_price", "fixed_price"] +class GroupedWithMeteredMinimumPriceBillableMetric(BaseModel): + id: str + + +class GroupedWithMeteredMinimumPriceBillingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class GroupedWithMeteredMinimumPriceCreditAllocation(BaseModel): + allows_rollover: bool + + currency: str + + +class GroupedWithMeteredMinimumPriceInvoicingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class GroupedWithMeteredMinimumPriceItem(BaseModel): + id: str + + name: str + + +class GroupedWithMeteredMinimumPriceMaximum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this maximum amount applies to. + + For plan/plan phase maximums, this can be a subset of prices. + """ + + maximum_amount: str + """Maximum amount applied""" + + +class GroupedWithMeteredMinimumPriceMinimum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this minimum amount applies to. + + For plan/plan phase minimums, this can be a subset of prices. + """ + + minimum_amount: str + """Minimum amount applied""" + + +class GroupedWithMeteredMinimumPrice(BaseModel): + id: str + + billable_metric: Optional[GroupedWithMeteredMinimumPriceBillableMetric] = None + + billing_cycle_configuration: GroupedWithMeteredMinimumPriceBillingCycleConfiguration + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + conversion_rate: Optional[float] = None + + created_at: datetime + + credit_allocation: Optional[GroupedWithMeteredMinimumPriceCreditAllocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + grouped_with_metered_minimum_config: Dict[str, object] + + invoicing_cycle_configuration: Optional[GroupedWithMeteredMinimumPriceInvoicingCycleConfiguration] = None + + item: GroupedWithMeteredMinimumPriceItem + + maximum: Optional[GroupedWithMeteredMinimumPriceMaximum] = None + + maximum_amount: Optional[str] = None + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum: Optional[GroupedWithMeteredMinimumPriceMinimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["grouped_with_metered_minimum"] = FieldInfo(alias="model_type") + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price"] + + +class MatrixWithDisplayNamePriceBillableMetric(BaseModel): + id: str + + +class MatrixWithDisplayNamePriceBillingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class MatrixWithDisplayNamePriceCreditAllocation(BaseModel): + allows_rollover: bool + + currency: str + + +class MatrixWithDisplayNamePriceInvoicingCycleConfiguration(BaseModel): + duration: int + + duration_unit: Literal["day", "month"] + + +class MatrixWithDisplayNamePriceItem(BaseModel): + id: str + + name: str + + +class MatrixWithDisplayNamePriceMaximum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this maximum amount applies to. + + For plan/plan phase maximums, this can be a subset of prices. + """ + + maximum_amount: str + """Maximum amount applied""" + + +class MatrixWithDisplayNamePriceMinimum(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this minimum amount applies to. + + For plan/plan phase minimums, this can be a subset of prices. + """ + + minimum_amount: str + """Minimum amount applied""" + + +class MatrixWithDisplayNamePrice(BaseModel): + id: str + + billable_metric: Optional[MatrixWithDisplayNamePriceBillableMetric] = None + + billing_cycle_configuration: MatrixWithDisplayNamePriceBillingCycleConfiguration + + cadence: Literal["one_time", "monthly", "quarterly", "semi_annual", "annual", "custom"] + + conversion_rate: Optional[float] = None + + created_at: datetime + + credit_allocation: Optional[MatrixWithDisplayNamePriceCreditAllocation] = None + + currency: str + + discount: Optional[Discount] = None + + external_price_id: Optional[str] = None + + fixed_price_quantity: Optional[float] = None + + invoicing_cycle_configuration: Optional[MatrixWithDisplayNamePriceInvoicingCycleConfiguration] = None + + item: MatrixWithDisplayNamePriceItem + + matrix_with_display_name_config: Dict[str, object] + + maximum: Optional[MatrixWithDisplayNamePriceMaximum] = None + + maximum_amount: Optional[str] = None + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum: Optional[MatrixWithDisplayNamePriceMinimum] = None + + minimum_amount: Optional[str] = None + + price_model_type: Literal["matrix_with_display_name"] = FieldInfo(alias="model_type") + + name: str + + plan_phase_order: Optional[int] = None + + price_type: Literal["usage_price", "fixed_price"] + + class BulkWithProrationPriceBillableMetric(BaseModel): id: str @@ -2660,6 +2884,8 @@ class GroupedTieredPackagePrice(BaseModel): UnitWithProrationPrice, GroupedAllocationPrice, GroupedWithProratedMinimumPrice, + GroupedWithMeteredMinimumPrice, + MatrixWithDisplayNamePrice, BulkWithProrationPrice, GroupedTieredPackagePrice, ], diff --git a/src/orb/types/price_create_params.py b/src/orb/types/price_create_params.py index c0bb199d..25e40b1d 100644 --- a/src/orb/types/price_create_params.py +++ b/src/orb/types/price_create_params.py @@ -82,6 +82,12 @@ "NewFloatingGroupedWithProratedMinimumPrice", "NewFloatingGroupedWithProratedMinimumPriceBillingCycleConfiguration", "NewFloatingGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "NewFloatingGroupedWithMeteredMinimumPrice", + "NewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration", + "NewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration", + "NewFloatingMatrixWithDisplayNamePrice", + "NewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration", + "NewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration", "NewFloatingBulkWithProrationPrice", "NewFloatingBulkWithProrationPriceBillingCycleConfiguration", "NewFloatingBulkWithProrationPriceInvoicingCycleConfiguration", @@ -1835,6 +1841,166 @@ class NewFloatingGroupedWithProratedMinimumPriceInvoicingCycleConfiguration(Type """The unit of billing period duration.""" +class NewFloatingGroupedWithMeteredMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_with_metered_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[NewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + +class NewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class NewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class NewFloatingMatrixWithDisplayNamePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + matrix_with_display_name_config: Required[Dict[str, object]] + + model_type: Required[Literal["matrix_with_display_name"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[NewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[NewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + +class NewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class NewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + class NewFloatingBulkWithProrationPrice(TypedDict, total=False): bulk_with_proration_config: Required[Dict[str, object]] @@ -2016,6 +2182,8 @@ class NewFloatingGroupedTieredPackagePriceInvoicingCycleConfiguration(TypedDict, NewFloatingUnitWithProrationPrice, NewFloatingGroupedAllocationPrice, NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPrice, + NewFloatingMatrixWithDisplayNamePrice, NewFloatingBulkWithProrationPrice, NewFloatingGroupedTieredPackagePrice, ] diff --git a/src/orb/types/shared/__init__.py b/src/orb/types/shared/__init__.py index 98c8e5c0..6089696e 100644 --- a/src/orb/types/shared/__init__.py +++ b/src/orb/types/shared/__init__.py @@ -1,5 +1,9 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .discount import Discount as Discount +from .trial_discount import TrialDiscount as TrialDiscount +from .amount_discount import AmountDiscount as AmountDiscount from .pagination_metadata import PaginationMetadata as PaginationMetadata +from .percentage_discount import PercentageDiscount as PercentageDiscount +from .invoice_level_discount import InvoiceLevelDiscount as InvoiceLevelDiscount from .billing_cycle_relative_date import BillingCycleRelativeDate as BillingCycleRelativeDate diff --git a/src/orb/types/shared/amount_discount.py b/src/orb/types/shared/amount_discount.py new file mode 100644 index 00000000..e9c80a97 --- /dev/null +++ b/src/orb/types/shared/amount_discount.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AmountDiscount"] + + +class AmountDiscount(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Literal["amount"] + + reason: Optional[str] = None diff --git a/src/orb/types/shared/discount.py b/src/orb/types/shared/discount.py index 866b378c..c2491612 100644 --- a/src/orb/types/shared/discount.py +++ b/src/orb/types/shared/discount.py @@ -5,44 +5,11 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from .trial_discount import TrialDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount -__all__ = ["Discount", "PercentageDiscount", "TrialDiscount", "UsageDiscount", "AmountDiscount"] - - -class PercentageDiscount(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Literal["percentage"] - - percentage_discount: float - """Only available if discount_type is `percentage`. - - This is a number between 0 and 1. - """ - - reason: Optional[str] = None - - -class TrialDiscount(BaseModel): - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Literal["trial"] - - reason: Optional[str] = None - - trial_amount_discount: Optional[str] = None - """Only available if discount_type is `trial`""" - - trial_percentage_discount: Optional[float] = None - """Only available if discount_type is `trial`""" +__all__ = ["Discount", "UsageDiscount"] class UsageDiscount(BaseModel): @@ -63,21 +30,6 @@ class UsageDiscount(BaseModel): reason: Optional[str] = None -class AmountDiscount(BaseModel): - amount_discount: str - """Only available if discount_type is `amount`.""" - - applies_to_price_ids: List[str] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Literal["amount"] - - reason: Optional[str] = None - - Discount: TypeAlias = Annotated[ Union[PercentageDiscount, TrialDiscount, UsageDiscount, AmountDiscount], PropertyInfo(discriminator="discount_type") ] diff --git a/src/orb/types/shared/invoice_level_discount.py b/src/orb/types/shared/invoice_level_discount.py new file mode 100644 index 00000000..57f7080d --- /dev/null +++ b/src/orb/types/shared/invoice_level_discount.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Annotated, TypeAlias + +from ..._utils import PropertyInfo +from .trial_discount import TrialDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount + +__all__ = ["InvoiceLevelDiscount"] + +InvoiceLevelDiscount: TypeAlias = Annotated[ + Union[PercentageDiscount, AmountDiscount, TrialDiscount], PropertyInfo(discriminator="discount_type") +] diff --git a/src/orb/types/shared/percentage_discount.py b/src/orb/types/shared/percentage_discount.py new file mode 100644 index 00000000..de989cd4 --- /dev/null +++ b/src/orb/types/shared/percentage_discount.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["PercentageDiscount"] + + +class PercentageDiscount(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Literal["percentage"] + + percentage_discount: float + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + reason: Optional[str] = None diff --git a/src/orb/types/shared/trial_discount.py b/src/orb/types/shared/trial_discount.py new file mode 100644 index 00000000..5abfa574 --- /dev/null +++ b/src/orb/types/shared/trial_discount.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["TrialDiscount"] + + +class TrialDiscount(BaseModel): + applies_to_price_ids: List[str] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Literal["trial"] + + reason: Optional[str] = None + + trial_amount_discount: Optional[str] = None + """Only available if discount_type is `trial`""" + + trial_percentage_discount: Optional[float] = None + """Only available if discount_type is `trial`""" diff --git a/src/orb/types/shared_params/__init__.py b/src/orb/types/shared_params/__init__.py index ed0e0225..9d0d3706 100644 --- a/src/orb/types/shared_params/__init__.py +++ b/src/orb/types/shared_params/__init__.py @@ -1,4 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .discount import Discount as Discount +from .trial_discount import TrialDiscount as TrialDiscount +from .amount_discount import AmountDiscount as AmountDiscount +from .percentage_discount import PercentageDiscount as PercentageDiscount from .billing_cycle_relative_date import BillingCycleRelativeDate as BillingCycleRelativeDate diff --git a/src/orb/types/shared_params/amount_discount.py b/src/orb/types/shared_params/amount_discount.py new file mode 100644 index 00000000..7915c7fe --- /dev/null +++ b/src/orb/types/shared_params/amount_discount.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AmountDiscount"] + + +class AmountDiscount(TypedDict, total=False): + amount_discount: Required[str] + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: Required[List[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Required[Literal["amount"]] + + reason: Optional[str] diff --git a/src/orb/types/shared_params/discount.py b/src/orb/types/shared_params/discount.py index 17e76491..93cbb8fd 100644 --- a/src/orb/types/shared_params/discount.py +++ b/src/orb/types/shared_params/discount.py @@ -5,43 +5,11 @@ from typing import List, Union, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["Discount", "PercentageDiscount", "TrialDiscount", "UsageDiscount", "AmountDiscount"] +from .trial_discount import TrialDiscount +from .amount_discount import AmountDiscount +from .percentage_discount import PercentageDiscount - -class PercentageDiscount(TypedDict, total=False): - applies_to_price_ids: Required[List[str]] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Required[Literal["percentage"]] - - percentage_discount: Required[float] - """Only available if discount_type is `percentage`. - - This is a number between 0 and 1. - """ - - reason: Optional[str] - - -class TrialDiscount(TypedDict, total=False): - applies_to_price_ids: Required[List[str]] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Required[Literal["trial"]] - - reason: Optional[str] - - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - - trial_percentage_discount: Optional[float] - """Only available if discount_type is `trial`""" +__all__ = ["Discount", "UsageDiscount"] class UsageDiscount(TypedDict, total=False): @@ -62,19 +30,4 @@ class UsageDiscount(TypedDict, total=False): reason: Optional[str] -class AmountDiscount(TypedDict, total=False): - amount_discount: Required[str] - """Only available if discount_type is `amount`.""" - - applies_to_price_ids: Required[List[str]] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ - - discount_type: Required[Literal["amount"]] - - reason: Optional[str] - - Discount: TypeAlias = Union[PercentageDiscount, TrialDiscount, UsageDiscount, AmountDiscount] diff --git a/src/orb/types/shared_params/percentage_discount.py b/src/orb/types/shared_params/percentage_discount.py new file mode 100644 index 00000000..c2b15ea7 --- /dev/null +++ b/src/orb/types/shared_params/percentage_discount.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PercentageDiscount"] + + +class PercentageDiscount(TypedDict, total=False): + applies_to_price_ids: Required[List[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Required[Literal["percentage"]] + + percentage_discount: Required[float] + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + reason: Optional[str] diff --git a/src/orb/types/shared_params/trial_discount.py b/src/orb/types/shared_params/trial_discount.py new file mode 100644 index 00000000..c4f15cab --- /dev/null +++ b/src/orb/types/shared_params/trial_discount.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["TrialDiscount"] + + +class TrialDiscount(TypedDict, total=False): + applies_to_price_ids: Required[List[str]] + """List of price_ids that this discount applies to. + + For plan/plan phase discounts, this can be a subset of prices. + """ + + discount_type: Required[Literal["trial"]] + + reason: Optional[str] + + trial_amount_discount: Optional[str] + """Only available if discount_type is `trial`""" + + trial_percentage_discount: Optional[float] + """Only available if discount_type is `trial`""" diff --git a/src/orb/types/subscription.py b/src/orb/types/subscription.py index 3c7a08d7..e5ecc9c1 100644 --- a/src/orb/types/subscription.py +++ b/src/orb/types/subscription.py @@ -35,6 +35,8 @@ class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + adjustment_type: Literal["amount_discount"] amount_discount: str @@ -46,32 +48,63 @@ class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): applies_to_price_ids: List[str] """The price IDs that this adjustment applies to.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + reason: Optional[str] = None """The reason for the adjustment.""" class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + adjustment_type: Literal["percentage_discount"] applies_to_price_ids: List[str] """The price IDs that this adjustment applies to.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + percentage_discount: float """ The percentage (as a value between 0 and 1) by which to discount the price intervals this adjustment applies to in a given billing period. """ + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + reason: Optional[str] = None """The reason for the adjustment.""" class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + adjustment_type: Literal["usage_discount"] applies_to_price_ids: List[str] """The price IDs that this adjustment applies to.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + reason: Optional[str] = None """The reason for the adjustment.""" @@ -83,11 +116,19 @@ class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + adjustment_type: Literal["minimum"] applies_to_price_ids: List[str] """The price IDs that this adjustment applies to.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + item_id: str """The item ID that revenue from this minimum will be attributed to.""" @@ -97,22 +138,36 @@ class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): adjustment applies to. """ + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + reason: Optional[str] = None """The reason for the adjustment.""" class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + adjustment_type: Literal["maximum"] applies_to_price_ids: List[str] """The price IDs that this adjustment applies to.""" + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + maximum_amount: str """ The maximum amount to charge in a given billing period for the prices this adjustment applies to. """ + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + reason: Optional[str] = None """The reason for the adjustment.""" diff --git a/src/orb/types/subscription_cancel_response.py b/src/orb/types/subscription_cancel_response.py new file mode 100644 index 00000000..ef4b970a --- /dev/null +++ b/src/orb/types/subscription_cancel_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionCancelResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionCancelResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_create_params.py b/src/orb/types/subscription_create_params.py index f88e5e01..72273456 100644 --- a/src/orb/types/subscription_create_params.py +++ b/src/orb/types/subscription_create_params.py @@ -10,57 +10,181 @@ __all__ = [ "SubscriptionCreateParams", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewPercentageDiscount", + "AddAdjustmentAdjustmentNewUsageDiscount", + "AddAdjustmentAdjustmentNewAmountDiscount", + "AddAdjustmentAdjustmentNewMinimum", + "AddAdjustmentAdjustmentNewMaximum", + "AddPrice", + "AddPriceDiscount", + "AddPricePrice", + "AddPricePriceNewSubscriptionUnitPrice", + "AddPricePriceNewSubscriptionUnitPriceUnitConfig", + "AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionPackagePrice", + "AddPricePriceNewSubscriptionPackagePricePackageConfig", + "AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionMatrixPrice", + "AddPricePriceNewSubscriptionMatrixPriceMatrixConfig", + "AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue", + "AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPrice", + "AddPricePriceNewSubscriptionTieredPriceTieredConfig", + "AddPricePriceNewSubscriptionTieredPriceTieredConfigTier", + "AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredBpsPrice", + "AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig", + "AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier", + "AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBpsPrice", + "AddPricePriceNewSubscriptionBpsPriceBpsConfig", + "AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkBpsPrice", + "AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig", + "AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier", + "AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkPrice", + "AddPricePriceNewSubscriptionBulkPriceBulkConfig", + "AddPricePriceNewSubscriptionBulkPriceBulkConfigTier", + "AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionThresholdTotalAmountPrice", + "AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPackagePrice", + "AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredWithMinimumPrice", + "AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithPercentPrice", + "AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionPackageWithAllocationPrice", + "AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTierWithProrationPrice", + "AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithProrationPrice", + "AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedAllocationPrice", + "AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkWithProrationPrice", + "AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration", "BillingCycleAnchorConfiguration", - "PriceOverride", - "PriceOverrideOverrideUnitPrice", - "PriceOverrideOverrideUnitPriceUnitConfig", - "PriceOverrideOverrideUnitPriceDiscount", - "PriceOverrideOverridePackagePrice", - "PriceOverrideOverridePackagePricePackageConfig", - "PriceOverrideOverridePackagePriceDiscount", - "PriceOverrideOverrideMatrixPrice", - "PriceOverrideOverrideMatrixPriceMatrixConfig", - "PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue", - "PriceOverrideOverrideMatrixPriceDiscount", - "PriceOverrideOverrideTieredPrice", - "PriceOverrideOverrideTieredPriceTieredConfig", - "PriceOverrideOverrideTieredPriceTieredConfigTier", - "PriceOverrideOverrideTieredPriceDiscount", - "PriceOverrideOverrideTieredBpsPrice", - "PriceOverrideOverrideTieredBpsPriceTieredBpsConfig", - "PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier", - "PriceOverrideOverrideTieredBpsPriceDiscount", - "PriceOverrideOverrideBpsPrice", - "PriceOverrideOverrideBpsPriceBpsConfig", - "PriceOverrideOverrideBpsPriceDiscount", - "PriceOverrideOverrideBulkBpsPrice", - "PriceOverrideOverrideBulkBpsPriceBulkBpsConfig", - "PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier", - "PriceOverrideOverrideBulkBpsPriceDiscount", - "PriceOverrideOverrideBulkPrice", - "PriceOverrideOverrideBulkPriceBulkConfig", - "PriceOverrideOverrideBulkPriceBulkConfigTier", - "PriceOverrideOverrideBulkPriceDiscount", - "PriceOverrideOverrideThresholdTotalAmountPrice", - "PriceOverrideOverrideThresholdTotalAmountPriceDiscount", - "PriceOverrideOverrideTieredPackagePrice", - "PriceOverrideOverrideTieredPackagePriceDiscount", - "PriceOverrideOverrideTieredWithMinimumPrice", - "PriceOverrideOverrideTieredWithMinimumPriceDiscount", - "PriceOverrideOverridePackageWithAllocationPrice", - "PriceOverrideOverridePackageWithAllocationPriceDiscount", - "PriceOverrideOverrideUnitWithPercentPrice", - "PriceOverrideOverrideUnitWithPercentPriceDiscount", - "PriceOverrideOverrideGroupedAllocationPrice", - "PriceOverrideOverrideGroupedAllocationPriceDiscount", - "PriceOverrideOverrideGroupedWithProratedMinimumPrice", - "PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount", - "PriceOverrideOverrideBulkWithProrationPrice", - "PriceOverrideOverrideBulkWithProrationPriceDiscount", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewUsageDiscount", + "ReplaceAdjustmentAdjustmentNewAmountDiscount", + "ReplaceAdjustmentAdjustmentNewMinimum", + "ReplaceAdjustmentAdjustmentNewMaximum", + "ReplacePrice", + "ReplacePriceDiscount", + "ReplacePricePrice", + "ReplacePricePriceNewSubscriptionUnitPrice", + "ReplacePricePriceNewSubscriptionUnitPriceUnitConfig", + "ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackagePrice", + "ReplacePricePriceNewSubscriptionPackagePricePackageConfig", + "ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionMatrixPrice", + "ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig", + "ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue", + "ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPrice", + "ReplacePricePriceNewSubscriptionTieredPriceTieredConfig", + "ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier", + "ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredBpsPrice", + "ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig", + "ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier", + "ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBpsPrice", + "ReplacePricePriceNewSubscriptionBpsPriceBpsConfig", + "ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkBpsPrice", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkPrice", + "ReplacePricePriceNewSubscriptionBulkPriceBulkConfig", + "ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier", + "ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPackagePrice", + "ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPrice", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithPercentPrice", + "ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPrice", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTierWithProrationPrice", + "ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithProrationPrice", + "ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedAllocationPrice", + "ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkWithProrationPrice", + "ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration", ] class SubscriptionCreateParams(TypedDict, total=False): + add_adjustments: Optional[Iterable[AddAdjustment]] + """Additional adjustments to be added to the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + add_prices: Optional[Iterable[AddPrice]] + """Additional prices to be added to the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + align_billing_with_subscription_start_date: bool auto_collection: Optional[bool] @@ -106,6 +230,14 @@ class SubscriptionCreateParams(TypedDict, total=False): to. Note that either this property or `plan_id` must be specified. """ + filter: Optional[str] + """An additional filter to apply to usage queries. + + This filter must be expressed as a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + """ + initial_phase_order: Optional[int] """The phase of the plan to start with""" @@ -138,62 +270,176 @@ class SubscriptionCreateParams(TypedDict, total=False): Note that either this property or `external_plan_id` must be specified. """ - price_overrides: Optional[Iterable[PriceOverride]] + plan_version_number: Optional[int] + """Specifies which version of the plan to subscribe to. + + If null, the default version will be used. + """ + + price_overrides: Optional[Iterable[object]] """Optionally provide a list of overrides for prices on the plan""" + remove_adjustments: Optional[Iterable[RemoveAdjustment]] + """Plan adjustments to be removed from the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + remove_prices: Optional[Iterable[RemovePrice]] + """Plan prices to be removed from the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Plan adjustments to be replaced with additional adjustments on the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + replace_prices: Optional[Iterable[ReplacePrice]] + """Plan prices to be replaced with additional prices on the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + trial_duration_days: Optional[int] + """The duration of the trial period in days. -class BillingCycleAnchorConfiguration(TypedDict, total=False): - day: Required[int] - """The day of the month on which the billing cycle is anchored. + If not provided, this defaults to the value specified in the plan. If `0` is + provided, the trial on the plan will be skipped. + """ - If the maximum number of days in a month is greater than this value, the last - day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April - means the billing period begins on the 30th. + +class AddAdjustmentAdjustmentNewPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["percentage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + percentage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. """ - month: Optional[int] - """The month on which the billing cycle is anchored (e.g. - a quarterly price anchored in February would have cycles starting February, May, - August, and November). +class AddAdjustmentAdjustmentNewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + usage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. """ - year: Optional[int] - """The year on which the billing cycle is anchored (e.g. - a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, - 2023, 2025, etc.). +class AddAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["amount_discount"]] + + amount_discount: Required[str] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. """ -class PriceOverrideOverrideUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" +class AddAdjustmentAdjustmentNewMinimum(TypedDict, total=False): + adjustment_type: Required[Literal["minimum"]] + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" -class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + item_id: Required[str] + """The item ID that revenue from this minimum will be attributed to.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + minimum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewMaximum(TypedDict, total=False): + adjustment_type: Required[Literal["maximum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + maximum_amount: Required[str] - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. - For plan/plan phase discounts, this can be a subset of prices. + Otherwise, it will be applied at the invoice level, possibly to multiple prices. """ + +AddAdjustmentAdjustment: TypeAlias = Union[ + AddAdjustmentAdjustmentNewPercentageDiscount, + AddAdjustmentAdjustmentNewUsageDiscount, + AddAdjustmentAdjustmentNewAmountDiscount, + AddAdjustmentAdjustmentNewMinimum, + AddAdjustmentAdjustmentNewMaximum, +] + + +class AddAdjustment(TypedDict, total=False): + adjustment: Required[AddAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the subscription.""" + + end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The end date of the adjustment interval. + + This is the date that the adjustment will stop affecting prices on the + subscription. If null, the adjustment will start when the phase or subscription + starts. + """ + + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" + + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the adjustment interval. + + This is the date that the adjustment will start affecting prices on the + subscription. If null, the adjustment will start when the phase or subscription + starts. + """ + + +class AddPriceDiscount(TypedDict, total=False): + discount_type: Required[Literal["percentage", "usage", "amount"]] + + amount_discount: Optional[str] + """Only available if discount_type is `amount`.""" + percentage_discount: Optional[float] """Only available if discount_type is `percentage`. This is a number between 0 and 1. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - usage_discount: Optional[float] """Only available if discount_type is `usage`. @@ -201,36 +447,101 @@ class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): """ -class PriceOverrideOverrideUnitPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionUnitPriceUnitConfig(TypedDict, total=False): + unit_amount: Required[str] + """Rate per unit of usage""" + + +class AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["unit"]] - unit_config: Required[PriceOverrideOverrideUnitPriceUnitConfig] + name: Required[str] + """The name of the price.""" + + unit_config: Required[AddPricePriceNewSubscriptionUnitPriceUnitConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideUnitPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): + +class AddPricePriceNewSubscriptionPackagePricePackageConfig(TypedDict, total=False): package_amount: Required[str] """A currency amount to rate usage by""" @@ -242,64 +553,96 @@ class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): """ -class PriceOverrideOverridePackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + model_type: Required[Literal["package"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverridePackagePrice(TypedDict, total=False): - id: Required[str] + package_config: Required[AddPricePriceNewSubscriptionPackagePricePackageConfig] - model_type: Required[Literal["package"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - package_config: Required[PriceOverrideOverridePackagePricePackageConfig] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverridePackagePriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): +class AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): dimension_values: Required[List[Optional[str]]] """One or two matrix keys to filter usage to this Matrix value by. @@ -311,75 +654,107 @@ class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=F """Unit price for the specified dimension_values""" -class PriceOverrideOverrideMatrixPriceMatrixConfig(TypedDict, total=False): +class AddPricePriceNewSubscriptionMatrixPriceMatrixConfig(TypedDict, total=False): default_unit_amount: Required[str] """Default per unit rate for any usage not bucketed into a specified matrix_value""" dimensions: Required[List[Optional[str]]] """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue]] + matrix_values: Required[Iterable[AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue]] """Matrix values for specified matrix grouping keys""" -class PriceOverrideOverrideMatrixPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionMatrixPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + matrix_config: Required[AddPricePriceNewSubscriptionMatrixPriceMatrixConfig] + model_type: Required[Literal["matrix"]] -class PriceOverrideOverrideMatrixPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - matrix_config: Required[PriceOverrideOverrideMatrixPriceMatrixConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["matrix"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideMatrixPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): + +class AddPricePriceNewSubscriptionTieredPriceTieredConfigTier(TypedDict, total=False): first_unit: Required[float] """Inclusive tier starting value""" @@ -390,69 +765,101 @@ class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): """Exclusive tier ending value. If null, this is treated as the last tier""" -class PriceOverrideOverrideTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredPriceTieredConfigTier]] +class AddPricePriceNewSubscriptionTieredPriceTieredConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredPriceTieredConfigTier]] """Tiers for rating based on total usage quantities into the specified tier""" -class PriceOverrideOverrideTieredPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionTieredPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + model_type: Required[Literal["tiered"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideTieredPrice(TypedDict, total=False): - id: Required[str] + tiered_config: Required[AddPricePriceNewSubscriptionTieredPriceTieredConfig] - model_type: Required[Literal["tiered"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - tiered_config: Required[PriceOverrideOverrideTieredPriceTieredConfig] + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideTieredPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): +class AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): bps: Required[float] """Per-event basis point rate""" @@ -466,72 +873,104 @@ class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=Fa """Per unit maximum to charge""" -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier]] +class AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier]] """ Tiers for a Graduated BPS pricing model, where usage is bucketed into specified tiers """ -class PriceOverrideOverrideTieredBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] - - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" - - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionTieredBpsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideTieredBpsPrice(TypedDict, total=False): - id: Required[str] + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["tiered_bps"]] - tiered_bps_config: Required[PriceOverrideOverrideTieredBpsPriceTieredBpsConfig] + name: Required[str] + """The name of the price.""" - conversion_rate: Optional[float] - """The per unit conversion rate of the price currency to the invoicing currency.""" + tiered_bps_config: Required[AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig] - currency: Optional[str] - """The currency of the price. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - If not provided, the currency of the plan will be used. + Only needed if the price is usage-based. """ - discount: Optional[PriceOverrideOverrideTieredBpsPriceDiscount] - """The subscription's override discount for the plan.""" + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): + +class AddPricePriceNewSubscriptionBpsPriceBpsConfig(TypedDict, total=False): bps: Required[float] """Basis point take rate per event""" @@ -539,64 +978,96 @@ class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): """Optional currency amount maximum to cap spend per event""" -class PriceOverrideOverrideBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBpsPrice(TypedDict, total=False): + bps_config: Required[AddPricePriceNewSubscriptionBpsPriceBpsConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bps"]] -class PriceOverrideOverrideBpsPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - bps_config: Required[PriceOverrideOverrideBpsPriceBpsConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["bps"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBpsPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): +class AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): bps: Required[float] """Basis points to rate on""" @@ -607,72 +1078,104 @@ class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False) """The maximum amount to charge for any one event""" -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier]] +class AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier]] """ Tiers for a bulk BPS pricing model where all usage is aggregated to a single tier based on total volume """ -class PriceOverrideOverrideBulkBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBulkBpsPrice(TypedDict, total=False): + bulk_bps_config: Required[AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bulk_bps"]] -class PriceOverrideOverrideBulkBpsPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - bulk_bps_config: Required[PriceOverrideOverrideBulkBpsPriceBulkBpsConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["bulk_bps"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBulkBpsPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): + +class AddPricePriceNewSubscriptionBulkPriceBulkConfigTier(TypedDict, total=False): unit_amount: Required[str] """Amount per unit""" @@ -680,539 +1183,3041 @@ class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): """Upper bound for this tier""" -class PriceOverrideOverrideBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkPriceBulkConfigTier]] +class AddPricePriceNewSubscriptionBulkPriceBulkConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkPriceBulkConfigTier]] """Bulk tiers for rating based on total usage volume""" -class PriceOverrideOverrideBulkPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBulkPrice(TypedDict, total=False): + bulk_config: Required[AddPricePriceNewSubscriptionBulkPriceBulkConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bulk"]] -class PriceOverrideOverrideBulkPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - bulk_config: Required[PriceOverrideOverrideBulkPriceBulkConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["bulk"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBulkPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideThresholdTotalAmountPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideThresholdTotalAmountPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionThresholdTotalAmountPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["threshold_total_amount"]] + name: Required[str] + """The name of the price.""" + threshold_total_amount_config: Required[Dict[str, object]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideThresholdTotalAmountPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideTieredPackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideTieredPackagePrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionTieredPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["tiered_package"]] + name: Required[str] + """The name of the price.""" + tiered_package_config: Required[Dict[str, object]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideTieredPackagePriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideTieredWithMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideTieredWithMinimumPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionTieredWithMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["tiered_with_minimum"]] + name: Required[str] + """The name of the price.""" + tiered_with_minimum_config: Required[Dict[str, object]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideTieredWithMinimumPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverridePackageWithAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverridePackageWithAllocationPrice(TypedDict, total=False): - id: Required[str] - model_type: Required[Literal["package_with_allocation"]] +class AddPricePriceNewSubscriptionUnitWithPercentPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionPackageWithAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionTierWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_allocation_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_prorated_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionBulkWithProrationPrice(TypedDict, total=False): + bulk_with_proration_config: Required[Dict[str, object]] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +AddPricePrice: TypeAlias = Union[ + AddPricePriceNewSubscriptionUnitPrice, + AddPricePriceNewSubscriptionPackagePrice, + AddPricePriceNewSubscriptionMatrixPrice, + AddPricePriceNewSubscriptionTieredPrice, + AddPricePriceNewSubscriptionTieredBpsPrice, + AddPricePriceNewSubscriptionBpsPrice, + AddPricePriceNewSubscriptionBulkBpsPrice, + AddPricePriceNewSubscriptionBulkPrice, + AddPricePriceNewSubscriptionThresholdTotalAmountPrice, + AddPricePriceNewSubscriptionTieredPackagePrice, + AddPricePriceNewSubscriptionTieredWithMinimumPrice, + AddPricePriceNewSubscriptionUnitWithPercentPrice, + AddPricePriceNewSubscriptionPackageWithAllocationPrice, + AddPricePriceNewSubscriptionTierWithProrationPrice, + AddPricePriceNewSubscriptionUnitWithProrationPrice, + AddPricePriceNewSubscriptionGroupedAllocationPrice, + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice, + AddPricePriceNewSubscriptionBulkWithProrationPrice, +] + + +class AddPrice(TypedDict, total=False): + discounts: Optional[Iterable[AddPriceDiscount]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for this price. + """ + + end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The end date of the price interval. + + This is the date that the price will stop billing on the subscription. If null, + billing will end when the phase or subscription ends. + """ + + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" + + maximum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for this price. + """ + + minimum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for this price. + """ + + plan_phase_order: Optional[int] + """The phase to add this price to.""" + + price: Optional[AddPricePrice] + """The definition of a new price to create and add to the subscription.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" + + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the price interval. + + This is the date that the price will start billing on the subscription. If null, + billing will start when the phase or subscription starts. + """ + + +class BillingCycleAnchorConfiguration(TypedDict, total=False): + day: Required[int] + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class RemoveAdjustment(TypedDict, total=False): + adjustment_id: Required[str] + """The id of the adjustment to remove on the subscription.""" + + +class RemovePrice(TypedDict, total=False): + external_price_id: Optional[str] + """The external price id of the price to remove on the subscription.""" + + price_id: Optional[str] + """The id of the price to remove on the subscription.""" + + +class ReplaceAdjustmentAdjustmentNewPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["percentage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + percentage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + usage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["amount_discount"]] + + amount_discount: Required[str] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewMinimum(TypedDict, total=False): + adjustment_type: Required[Literal["minimum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + item_id: Required[str] + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewMaximum(TypedDict, total=False): + adjustment_type: Required[Literal["maximum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + maximum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + ReplaceAdjustmentAdjustmentNewPercentageDiscount, + ReplaceAdjustmentAdjustmentNewUsageDiscount, + ReplaceAdjustmentAdjustmentNewAmountDiscount, + ReplaceAdjustmentAdjustmentNewMinimum, + ReplaceAdjustmentAdjustmentNewMaximum, +] + + +class ReplaceAdjustment(TypedDict, total=False): + adjustment: Required[ReplaceAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the subscription.""" + + replaces_adjustment_id: Required[str] + """The id of the adjustment on the plan to replace in the subscription.""" + + +class ReplacePriceDiscount(TypedDict, total=False): + discount_type: Required[Literal["percentage", "usage", "amount"]] + + amount_discount: Optional[str] + """Only available if discount_type is `amount`.""" + + percentage_discount: Optional[float] + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + usage_discount: Optional[float] + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +class ReplacePricePriceNewSubscriptionUnitPriceUnitConfig(TypedDict, total=False): + unit_amount: Required[str] + """Rate per unit of usage""" + + +class ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit"]] + + name: Required[str] + """The name of the price.""" + + unit_config: Required[ReplacePricePriceNewSubscriptionUnitPriceUnitConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionPackagePricePackageConfig(TypedDict, total=False): + package_amount: Required[str] + """A currency amount to rate usage by""" + + package_size: Required[int] + """An integer amount to represent package size. + + For example, 1000 here would divide usage by 1000 before multiplying by + package_amount in rating + """ + + +class ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["package"]] + + name: Required[str] + """The name of the price.""" + + package_config: Required[ReplacePricePriceNewSubscriptionPackagePricePackageConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): + dimension_values: Required[List[Optional[str]]] + """One or two matrix keys to filter usage to this Matrix value by. + + For example, ["region", "tier"] could be used to filter cloud usage by a cloud + region and an instance tier. + """ + + unit_amount: Required[str] + """Unit price for the specified dimension_values""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig(TypedDict, total=False): + default_unit_amount: Required[str] + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: Required[List[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: Required[Iterable[ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue]] + """Matrix values for specified matrix grouping keys""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionMatrixPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + matrix_config: Required[ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig] + + model_type: Required[Literal["matrix"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier(TypedDict, total=False): + first_unit: Required[float] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + last_unit: Optional[float] + """Exclusive tier ending value. If null, this is treated as the last tier""" + + +class ReplacePricePriceNewSubscriptionTieredPriceTieredConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier]] + """Tiers for rating based on total usage quantities into the specified tier""" + + +class ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered"]] + + name: Required[str] + """The name of the price.""" + + tiered_config: Required[ReplacePricePriceNewSubscriptionTieredPriceTieredConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): + bps: Required[float] + """Per-event basis point rate""" + + minimum_amount: Required[str] + """Inclusive tier starting value""" + + maximum_amount: Optional[str] + """Exclusive tier ending value""" + + per_unit_maximum: Optional[str] + """Per unit maximum to charge""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier]] + """ + Tiers for a Graduated BPS pricing model, where usage is bucketed into specified + tiers + """ + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_bps"]] + + name: Required[str] + """The name of the price.""" + + tiered_bps_config: Required[ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBpsPriceBpsConfig(TypedDict, total=False): + bps: Required[float] + """Basis point take rate per event""" + + per_unit_maximum: Optional[str] + """Optional currency amount maximum to cap spend per event""" + + +class ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBpsPrice(TypedDict, total=False): + bps_config: Required[ReplacePricePriceNewSubscriptionBpsPriceBpsConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bps"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): + bps: Required[float] + """Basis points to rate on""" + + maximum_amount: Optional[str] + """Upper bound for tier""" + + per_unit_maximum: Optional[str] + """The maximum amount to charge for any one event""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier]] + """ + Tiers for a bulk BPS pricing model where all usage is aggregated to a single + tier based on total volume + """ + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPrice(TypedDict, total=False): + bulk_bps_config: Required[ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk_bps"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier(TypedDict, total=False): + unit_amount: Required[str] + """Amount per unit""" + + maximum_units: Optional[float] + """Upper bound for this tier""" + + +class ReplacePricePriceNewSubscriptionBulkPriceBulkConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +class ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkPrice(TypedDict, total=False): + bulk_config: Required[ReplacePricePriceNewSubscriptionBulkPriceBulkConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["threshold_total_amount"]] + + name: Required[str] + """The name of the price.""" + + threshold_total_amount_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_package"]] + + name: Required[str] + """The name of the price.""" + + tiered_package_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_minimum"]] + + name: Required[str] + """The name of the price.""" + + tiered_with_minimum_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + + name: Required[str] + """The name of the price.""" package_with_allocation_config: Required[Dict[str, object]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverridePackageWithAllocationPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideUnitWithPercentPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideUnitWithPercentPrice(TypedDict, total=False): - id: Required[str] - model_type: Required[Literal["unit_with_percent"]] +class ReplacePricePriceNewSubscriptionTierWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - unit_with_percent_config: Required[Dict[str, object]] + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideUnitWithPercentPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideGroupedAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. +class ReplacePricePriceNewSubscriptionUnitWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - This is a number between 0 and 1. + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - Number of usage units that this discount is for + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideGroupedAllocationPrice(TypedDict, total=False): - id: Required[str] +class ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" grouped_allocation_config: Required[Dict[str, object]] + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["grouped_allocation"]] + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideGroupedAllocationPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration( + TypedDict, total=False +): + duration: Required[int] + """The duration of the billing period.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideGroupedWithProratedMinimumPrice(TypedDict, total=False): - id: Required[str] + +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" grouped_with_prorated_minimum_config: Required[Dict[str, object]] + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["grouped_with_prorated_minimum"]] + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideBulkWithProrationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideBulkWithProrationPrice(TypedDict, total=False): - id: Required[str] +class ReplacePricePriceNewSubscriptionBulkWithProrationPrice(TypedDict, total=False): bulk_with_proration_config: Required[Dict[str, object]] + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bulk_with_proration"]] + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - If not provided, the currency of the plan will be used. + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +ReplacePricePrice: TypeAlias = Union[ + ReplacePricePriceNewSubscriptionUnitPrice, + ReplacePricePriceNewSubscriptionPackagePrice, + ReplacePricePriceNewSubscriptionMatrixPrice, + ReplacePricePriceNewSubscriptionTieredPrice, + ReplacePricePriceNewSubscriptionTieredBpsPrice, + ReplacePricePriceNewSubscriptionBpsPrice, + ReplacePricePriceNewSubscriptionBulkBpsPrice, + ReplacePricePriceNewSubscriptionBulkPrice, + ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice, + ReplacePricePriceNewSubscriptionTieredPackagePrice, + ReplacePricePriceNewSubscriptionTieredWithMinimumPrice, + ReplacePricePriceNewSubscriptionUnitWithPercentPrice, + ReplacePricePriceNewSubscriptionPackageWithAllocationPrice, + ReplacePricePriceNewSubscriptionTierWithProrationPrice, + ReplacePricePriceNewSubscriptionUnitWithProrationPrice, + ReplacePricePriceNewSubscriptionGroupedAllocationPrice, + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice, + ReplacePricePriceNewSubscriptionBulkWithProrationPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the subscription.""" + + discounts: Optional[Iterable[ReplacePriceDiscount]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for the replacement price. """ - discount: Optional[PriceOverrideOverrideBulkWithProrationPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """The new quantity of the price, if the price is a fixed price.""" maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for the replacement price. + """ minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" - - -PriceOverride: TypeAlias = Union[ - PriceOverrideOverrideUnitPrice, - PriceOverrideOverridePackagePrice, - PriceOverrideOverrideMatrixPrice, - PriceOverrideOverrideTieredPrice, - PriceOverrideOverrideTieredBpsPrice, - PriceOverrideOverrideBpsPrice, - PriceOverrideOverrideBulkBpsPrice, - PriceOverrideOverrideBulkPrice, - PriceOverrideOverrideThresholdTotalAmountPrice, - PriceOverrideOverrideTieredPackagePrice, - PriceOverrideOverrideTieredWithMinimumPrice, - PriceOverrideOverridePackageWithAllocationPrice, - PriceOverrideOverrideUnitWithPercentPrice, - PriceOverrideOverrideGroupedAllocationPrice, - PriceOverrideOverrideGroupedWithProratedMinimumPrice, - PriceOverrideOverrideBulkWithProrationPrice, -] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for the replacement price. + """ + + price: Optional[ReplacePricePrice] + """The definition of a new price to create and add to the subscription.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" diff --git a/src/orb/types/subscription_create_response.py b/src/orb/types/subscription_create_response.py new file mode 100644 index 00000000..b4fa41f7 --- /dev/null +++ b/src/orb/types/subscription_create_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionCreateResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionCreateResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_price_intervals_params.py b/src/orb/types/subscription_price_intervals_params.py index eb652b2c..6718c2e8 100644 --- a/src/orb/types/subscription_price_intervals_params.py +++ b/src/orb/types/subscription_price_intervals_params.py @@ -94,6 +94,12 @@ "AddPriceNewFloatingGroupedWithProratedMinimumPrice", "AddPriceNewFloatingGroupedWithProratedMinimumPriceBillingCycleConfiguration", "AddPriceNewFloatingGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "AddPriceNewFloatingGroupedWithMeteredMinimumPrice", + "AddPriceNewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration", + "AddPriceNewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration", + "AddPriceNewFloatingMatrixWithDisplayNamePrice", + "AddPriceNewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration", + "AddPriceNewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration", "AddPriceNewFloatingBulkWithProrationPrice", "AddPriceNewFloatingBulkWithProrationPriceBillingCycleConfiguration", "AddPriceNewFloatingBulkWithProrationPriceInvoicingCycleConfiguration", @@ -103,6 +109,7 @@ "AddAdjustment", "AddAdjustmentAdjustment", "AddAdjustmentAdjustmentNewPercentageDiscount", + "AddAdjustmentAdjustmentNewUsageDiscount", "AddAdjustmentAdjustmentNewAmountDiscount", "AddAdjustmentAdjustmentNewMinimum", "AddAdjustmentAdjustmentNewMaximum", @@ -1934,6 +1941,168 @@ class AddPriceNewFloatingGroupedWithProratedMinimumPrice(TypedDict, total=False) """ +class AddPriceNewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingGroupedWithMeteredMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + grouped_with_metered_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_metered_minimum"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPriceNewFloatingGroupedWithMeteredMinimumPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPriceNewFloatingGroupedWithMeteredMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + +class AddPriceNewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPriceNewFloatingMatrixWithDisplayNamePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + currency: Required[str] + """An ISO 4217 currency string for which this price is billed in.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + matrix_with_display_name_config: Required[Dict[str, object]] + + model_type: Required[Literal["matrix_with_display_name"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPriceNewFloatingMatrixWithDisplayNamePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[AddPriceNewFloatingMatrixWithDisplayNamePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + class AddPriceNewFloatingBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): duration: Required[int] """The duration of the billing period.""" @@ -2115,6 +2284,8 @@ class AddPriceNewFloatingGroupedTieredPackagePrice(TypedDict, total=False): AddPriceNewFloatingUnitWithProrationPrice, AddPriceNewFloatingGroupedAllocationPrice, AddPriceNewFloatingGroupedWithProratedMinimumPrice, + AddPriceNewFloatingGroupedWithMeteredMinimumPrice, + AddPriceNewFloatingMatrixWithDisplayNamePrice, AddPriceNewFloatingBulkWithProrationPrice, AddPriceNewFloatingGroupedTieredPackagePrice, ] @@ -2174,6 +2345,27 @@ class AddAdjustmentAdjustmentNewPercentageDiscount(TypedDict, total=False): percentage_discount: Required[float] + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + usage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + class AddAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): adjustment_type: Required[Literal["amount_discount"]] @@ -2183,6 +2375,12 @@ class AddAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): applies_to_price_ids: Required[List[str]] """The set of price IDs to which this adjustment applies.""" + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + class AddAdjustmentAdjustmentNewMinimum(TypedDict, total=False): adjustment_type: Required[Literal["minimum"]] @@ -2195,6 +2393,12 @@ class AddAdjustmentAdjustmentNewMinimum(TypedDict, total=False): minimum_amount: Required[str] + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + class AddAdjustmentAdjustmentNewMaximum(TypedDict, total=False): adjustment_type: Required[Literal["maximum"]] @@ -2204,9 +2408,16 @@ class AddAdjustmentAdjustmentNewMaximum(TypedDict, total=False): maximum_amount: Required[str] + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + AddAdjustmentAdjustment: TypeAlias = Union[ AddAdjustmentAdjustmentNewPercentageDiscount, + AddAdjustmentAdjustmentNewUsageDiscount, AddAdjustmentAdjustmentNewAmountDiscount, AddAdjustmentAdjustmentNewMinimum, AddAdjustmentAdjustmentNewMaximum, diff --git a/src/orb/types/subscription_price_intervals_response.py b/src/orb/types/subscription_price_intervals_response.py new file mode 100644 index 00000000..a83dcd42 --- /dev/null +++ b/src/orb/types/subscription_price_intervals_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionPriceIntervalsResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionPriceIntervalsResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_schedule_plan_change_params.py b/src/orb/types/subscription_schedule_plan_change_params.py index c7e06d4e..6b3c7074 100644 --- a/src/orb/types/subscription_schedule_plan_change_params.py +++ b/src/orb/types/subscription_schedule_plan_change_params.py @@ -10,58 +10,183 @@ __all__ = [ "SubscriptionSchedulePlanChangeParams", - "PriceOverride", - "PriceOverrideOverrideUnitPrice", - "PriceOverrideOverrideUnitPriceUnitConfig", - "PriceOverrideOverrideUnitPriceDiscount", - "PriceOverrideOverridePackagePrice", - "PriceOverrideOverridePackagePricePackageConfig", - "PriceOverrideOverridePackagePriceDiscount", - "PriceOverrideOverrideMatrixPrice", - "PriceOverrideOverrideMatrixPriceMatrixConfig", - "PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue", - "PriceOverrideOverrideMatrixPriceDiscount", - "PriceOverrideOverrideTieredPrice", - "PriceOverrideOverrideTieredPriceTieredConfig", - "PriceOverrideOverrideTieredPriceTieredConfigTier", - "PriceOverrideOverrideTieredPriceDiscount", - "PriceOverrideOverrideTieredBpsPrice", - "PriceOverrideOverrideTieredBpsPriceTieredBpsConfig", - "PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier", - "PriceOverrideOverrideTieredBpsPriceDiscount", - "PriceOverrideOverrideBpsPrice", - "PriceOverrideOverrideBpsPriceBpsConfig", - "PriceOverrideOverrideBpsPriceDiscount", - "PriceOverrideOverrideBulkBpsPrice", - "PriceOverrideOverrideBulkBpsPriceBulkBpsConfig", - "PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier", - "PriceOverrideOverrideBulkBpsPriceDiscount", - "PriceOverrideOverrideBulkPrice", - "PriceOverrideOverrideBulkPriceBulkConfig", - "PriceOverrideOverrideBulkPriceBulkConfigTier", - "PriceOverrideOverrideBulkPriceDiscount", - "PriceOverrideOverrideThresholdTotalAmountPrice", - "PriceOverrideOverrideThresholdTotalAmountPriceDiscount", - "PriceOverrideOverrideTieredPackagePrice", - "PriceOverrideOverrideTieredPackagePriceDiscount", - "PriceOverrideOverrideTieredWithMinimumPrice", - "PriceOverrideOverrideTieredWithMinimumPriceDiscount", - "PriceOverrideOverridePackageWithAllocationPrice", - "PriceOverrideOverridePackageWithAllocationPriceDiscount", - "PriceOverrideOverrideUnitWithPercentPrice", - "PriceOverrideOverrideUnitWithPercentPriceDiscount", - "PriceOverrideOverrideGroupedAllocationPrice", - "PriceOverrideOverrideGroupedAllocationPriceDiscount", - "PriceOverrideOverrideGroupedWithProratedMinimumPrice", - "PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount", - "PriceOverrideOverrideBulkWithProrationPrice", - "PriceOverrideOverrideBulkWithProrationPriceDiscount", + "AddAdjustment", + "AddAdjustmentAdjustment", + "AddAdjustmentAdjustmentNewPercentageDiscount", + "AddAdjustmentAdjustmentNewUsageDiscount", + "AddAdjustmentAdjustmentNewAmountDiscount", + "AddAdjustmentAdjustmentNewMinimum", + "AddAdjustmentAdjustmentNewMaximum", + "AddPrice", + "AddPriceDiscount", + "AddPricePrice", + "AddPricePriceNewSubscriptionUnitPrice", + "AddPricePriceNewSubscriptionUnitPriceUnitConfig", + "AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionPackagePrice", + "AddPricePriceNewSubscriptionPackagePricePackageConfig", + "AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionMatrixPrice", + "AddPricePriceNewSubscriptionMatrixPriceMatrixConfig", + "AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue", + "AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPrice", + "AddPricePriceNewSubscriptionTieredPriceTieredConfig", + "AddPricePriceNewSubscriptionTieredPriceTieredConfigTier", + "AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredBpsPrice", + "AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig", + "AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier", + "AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBpsPrice", + "AddPricePriceNewSubscriptionBpsPriceBpsConfig", + "AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkBpsPrice", + "AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig", + "AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier", + "AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkPrice", + "AddPricePriceNewSubscriptionBulkPriceBulkConfig", + "AddPricePriceNewSubscriptionBulkPriceBulkConfigTier", + "AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionThresholdTotalAmountPrice", + "AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPackagePrice", + "AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredWithMinimumPrice", + "AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithPercentPrice", + "AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionPackageWithAllocationPrice", + "AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionTierWithProrationPrice", + "AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithProrationPrice", + "AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedAllocationPrice", + "AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkWithProrationPrice", + "AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration", + "AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration", + "BillingCycleAnchorConfiguration", + "RemoveAdjustment", + "RemovePrice", + "ReplaceAdjustment", + "ReplaceAdjustmentAdjustment", + "ReplaceAdjustmentAdjustmentNewPercentageDiscount", + "ReplaceAdjustmentAdjustmentNewUsageDiscount", + "ReplaceAdjustmentAdjustmentNewAmountDiscount", + "ReplaceAdjustmentAdjustmentNewMinimum", + "ReplaceAdjustmentAdjustmentNewMaximum", + "ReplacePrice", + "ReplacePriceDiscount", + "ReplacePricePrice", + "ReplacePricePriceNewSubscriptionUnitPrice", + "ReplacePricePriceNewSubscriptionUnitPriceUnitConfig", + "ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackagePrice", + "ReplacePricePriceNewSubscriptionPackagePricePackageConfig", + "ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionMatrixPrice", + "ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig", + "ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue", + "ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPrice", + "ReplacePricePriceNewSubscriptionTieredPriceTieredConfig", + "ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier", + "ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredBpsPrice", + "ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig", + "ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier", + "ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBpsPrice", + "ReplacePricePriceNewSubscriptionBpsPriceBpsConfig", + "ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkBpsPrice", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier", + "ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkPrice", + "ReplacePricePriceNewSubscriptionBulkPriceBulkConfig", + "ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier", + "ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPackagePrice", + "ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPrice", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithPercentPrice", + "ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPrice", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTierWithProrationPrice", + "ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithProrationPrice", + "ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedAllocationPrice", + "ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkWithProrationPrice", + "ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration", + "ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration", ] class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): change_option: Required[Literal["requested_date", "end_of_subscription_term", "immediate"]] + add_adjustments: Optional[Iterable[AddAdjustment]] + """Additional adjustments to be added to the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + add_prices: Optional[Iterable[AddPrice]] + """Additional prices to be added to the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + align_billing_with_plan_change_date: Optional[bool] """[DEPRECATED] Use billing_cycle_alignment instead. @@ -82,6 +207,8 @@ class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): billing cycle alignment. """ + billing_cycle_anchor_configuration: Optional[BillingCycleAnchorConfiguration] + change_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """The date that the plan change should take effect. @@ -110,6 +237,14 @@ class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): to. Note that either this property or `plan_id` must be specified. """ + filter: Optional[str] + """An additional filter to apply to usage queries. + + This filter must be expressed as a boolean + [computed property](../guides/extensibility/advanced-metrics#computed-properties). + If null, usage queries will not include any additional filter. + """ + initial_phase_order: Optional[int] """The phase of the plan to start with""" @@ -135,36 +270,174 @@ class SubscriptionSchedulePlanChangeParams(TypedDict, total=False): Note that either this property or `external_plan_id` must be specified. """ - price_overrides: Optional[Iterable[PriceOverride]] + plan_version_number: Optional[int] + """Specifies which version of the plan to change to. + + If null, the default version will be used. + """ + + price_overrides: Optional[Iterable[object]] """Optionally provide a list of overrides for prices on the plan""" + remove_adjustments: Optional[Iterable[RemoveAdjustment]] + """Plan adjustments to be removed from the subscription. -class PriceOverrideOverrideUnitPriceUnitConfig(TypedDict, total=False): - unit_amount: Required[str] - """Rate per unit of usage""" + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + remove_prices: Optional[Iterable[RemovePrice]] + """Plan prices to be removed from the subscription. -class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + replace_adjustments: Optional[Iterable[ReplaceAdjustment]] + """Plan adjustments to be replaced with additional adjustments on the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + replace_prices: Optional[Iterable[ReplacePrice]] + """Plan prices to be replaced with additional prices on the subscription. + + (Only available for accounts that have migrated off of legacy subscription + overrides) + """ + + trial_duration_days: Optional[int] + """The duration of the trial period in days. + + If not provided, this defaults to the value specified in the plan. If `0` is + provided, the trial on the plan will be skipped. + """ + + +class AddAdjustmentAdjustmentNewPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["percentage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + percentage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + usage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["amount_discount"]] + + amount_discount: Required[str] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewMinimum(TypedDict, total=False): + adjustment_type: Required[Literal["minimum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + item_id: Required[str] + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class AddAdjustmentAdjustmentNewMaximum(TypedDict, total=False): + adjustment_type: Required[Literal["maximum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + maximum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. +AddAdjustmentAdjustment: TypeAlias = Union[ + AddAdjustmentAdjustmentNewPercentageDiscount, + AddAdjustmentAdjustmentNewUsageDiscount, + AddAdjustmentAdjustmentNewAmountDiscount, + AddAdjustmentAdjustmentNewMinimum, + AddAdjustmentAdjustmentNewMaximum, +] + + +class AddAdjustment(TypedDict, total=False): + adjustment: Required[AddAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the subscription.""" + + end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The end date of the adjustment interval. + + This is the date that the adjustment will stop affecting prices on the + subscription. If null, the adjustment will start when the phase or subscription + starts. + """ + + plan_phase_order: Optional[int] + """The phase to add this adjustment to.""" + + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the adjustment interval. + + This is the date that the adjustment will start affecting prices on the + subscription. If null, the adjustment will start when the phase or subscription + starts. """ + +class AddPriceDiscount(TypedDict, total=False): + discount_type: Required[Literal["percentage", "usage", "amount"]] + + amount_discount: Optional[str] + """Only available if discount_type is `amount`.""" + percentage_discount: Optional[float] """Only available if discount_type is `percentage`. This is a number between 0 and 1. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - usage_discount: Optional[float] """Only available if discount_type is `usage`. @@ -172,36 +445,101 @@ class PriceOverrideOverrideUnitPriceDiscount(TypedDict, total=False): """ -class PriceOverrideOverrideUnitPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionUnitPriceUnitConfig(TypedDict, total=False): + unit_amount: Required[str] + """Rate per unit of usage""" + + +class AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["unit"]] - unit_config: Required[PriceOverrideOverrideUnitPriceUnitConfig] + name: Required[str] + """The name of the price.""" + + unit_config: Required[AddPricePriceNewSubscriptionUnitPriceUnitConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideUnitPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): +class AddPricePriceNewSubscriptionPackagePricePackageConfig(TypedDict, total=False): package_amount: Required[str] """A currency amount to rate usage by""" @@ -213,64 +551,96 @@ class PriceOverrideOverridePackagePricePackageConfig(TypedDict, total=False): """ -class PriceOverrideOverridePackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + model_type: Required[Literal["package"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverridePackagePrice(TypedDict, total=False): - id: Required[str] + package_config: Required[AddPricePriceNewSubscriptionPackagePricePackageConfig] - model_type: Required[Literal["package"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - package_config: Required[PriceOverrideOverridePackagePricePackageConfig] + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverridePackagePriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): +class AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): dimension_values: Required[List[Optional[str]]] """One or two matrix keys to filter usage to this Matrix value by. @@ -282,75 +652,107 @@ class PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue(TypedDict, total=F """Unit price for the specified dimension_values""" -class PriceOverrideOverrideMatrixPriceMatrixConfig(TypedDict, total=False): +class AddPricePriceNewSubscriptionMatrixPriceMatrixConfig(TypedDict, total=False): default_unit_amount: Required[str] """Default per unit rate for any usage not bucketed into a specified matrix_value""" dimensions: Required[List[Optional[str]]] """One or two event property values to evaluate matrix groups by""" - matrix_values: Required[Iterable[PriceOverrideOverrideMatrixPriceMatrixConfigMatrixValue]] + matrix_values: Required[Iterable[AddPricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue]] """Matrix values for specified matrix grouping keys""" -class PriceOverrideOverrideMatrixPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionMatrixPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + matrix_config: Required[AddPricePriceNewSubscriptionMatrixPriceMatrixConfig] + + model_type: Required[Literal["matrix"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideMatrixPrice(TypedDict, total=False): - id: Required[str] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - matrix_config: Required[PriceOverrideOverrideMatrixPriceMatrixConfig] + Only needed if the price is usage-based. + """ - model_type: Required[Literal["matrix"]] + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideMatrixPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionTieredPriceTieredConfigTier(TypedDict, total=False): first_unit: Required[float] """Inclusive tier starting value""" @@ -361,69 +763,101 @@ class PriceOverrideOverrideTieredPriceTieredConfigTier(TypedDict, total=False): """Exclusive tier ending value. If null, this is treated as the last tier""" -class PriceOverrideOverrideTieredPriceTieredConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredPriceTieredConfigTier]] +class AddPricePriceNewSubscriptionTieredPriceTieredConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredPriceTieredConfigTier]] """Tiers for rating based on total usage quantities into the specified tier""" -class PriceOverrideOverrideTieredPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionTieredPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + model_type: Required[Literal["tiered"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideTieredPrice(TypedDict, total=False): - id: Required[str] + tiered_config: Required[AddPricePriceNewSubscriptionTieredPriceTieredConfig] - model_type: Required[Literal["tiered"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - tiered_config: Required[PriceOverrideOverrideTieredPriceTieredConfig] + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideTieredPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): +class AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): bps: Required[float] """Per-event basis point rate""" @@ -437,72 +871,104 @@ class PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier(TypedDict, total=Fa """Per unit maximum to charge""" -class PriceOverrideOverrideTieredBpsPriceTieredBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideTieredBpsPriceTieredBpsConfigTier]] +class AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier]] """ Tiers for a Graduated BPS pricing model, where usage is bucketed into specified tiers """ -class PriceOverrideOverrideTieredBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionTieredBpsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - Number of usage units that this discount is for - """ + model_type: Required[Literal["tiered_bps"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideTieredBpsPrice(TypedDict, total=False): - id: Required[str] + tiered_bps_config: Required[AddPricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig] - model_type: Required[Literal["tiered_bps"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - tiered_bps_config: Required[PriceOverrideOverrideTieredBpsPriceTieredBpsConfig] + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideTieredBpsPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): +class AddPricePriceNewSubscriptionBpsPriceBpsConfig(TypedDict, total=False): bps: Required[float] """Basis point take rate per event""" @@ -510,64 +976,96 @@ class PriceOverrideOverrideBpsPriceBpsConfig(TypedDict, total=False): """Optional currency amount maximum to cap spend per event""" -class PriceOverrideOverrideBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBpsPrice(TypedDict, total=False): + bps_config: Required[AddPricePriceNewSubscriptionBpsPriceBpsConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bps"]] -class PriceOverrideOverrideBpsPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - bps_config: Required[PriceOverrideOverrideBpsPriceBpsConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["bps"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBpsPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): +class AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): bps: Required[float] """Basis points to rate on""" @@ -578,72 +1076,104 @@ class PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False) """The maximum amount to charge for any one event""" -class PriceOverrideOverrideBulkBpsPriceBulkBpsConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkBpsPriceBulkBpsConfigTier]] +class AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier]] """ Tiers for a bulk BPS pricing model where all usage is aggregated to a single tier based on total volume """ -class PriceOverrideOverrideBulkBpsPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBulkBpsPrice(TypedDict, total=False): + bulk_bps_config: Required[AddPricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk_bps"]] + name: Required[str] + """The name of the price.""" -class PriceOverrideOverrideBulkBpsPrice(TypedDict, total=False): - id: Required[str] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - bulk_bps_config: Required[PriceOverrideOverrideBulkBpsPriceBulkBpsConfig] + Only needed if the price is usage-based. + """ - model_type: Required[Literal["bulk_bps"]] + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBulkBpsPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionBulkPriceBulkConfigTier(TypedDict, total=False): unit_amount: Required[str] """Amount per unit""" @@ -651,539 +1181,3041 @@ class PriceOverrideOverrideBulkPriceBulkConfigTier(TypedDict, total=False): """Upper bound for this tier""" -class PriceOverrideOverrideBulkPriceBulkConfig(TypedDict, total=False): - tiers: Required[Iterable[PriceOverrideOverrideBulkPriceBulkConfigTier]] +class AddPricePriceNewSubscriptionBulkPriceBulkConfig(TypedDict, total=False): + tiers: Required[Iterable[AddPricePriceNewSubscriptionBulkPriceBulkConfigTier]] """Bulk tiers for rating based on total usage volume""" -class PriceOverrideOverrideBulkPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] +class AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. - For plan/plan phase discounts, this can be a subset of prices. - """ +class AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - This is a number between 0 and 1. - """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" +class AddPricePriceNewSubscriptionBulkPrice(TypedDict, total=False): + bulk_config: Required[AddPricePriceNewSubscriptionBulkPriceBulkConfig] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - Number of usage units that this discount is for - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bulk"]] -class PriceOverrideOverrideBulkPrice(TypedDict, total=False): - id: Required[str] + name: Required[str] + """The name of the price.""" - bulk_config: Required[PriceOverrideOverrideBulkPriceBulkConfig] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - model_type: Required[Literal["bulk"]] + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideBulkPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideThresholdTotalAmountPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + +class AddPricePriceNewSubscriptionThresholdTotalAmountPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" -class PriceOverrideOverrideThresholdTotalAmountPrice(TypedDict, total=False): - id: Required[str] + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["threshold_total_amount"]] - threshold_total_amount_config: Required[Dict[str, object]] + name: Required[str] + """The name of the price.""" - conversion_rate: Optional[float] - """The per unit conversion rate of the price currency to the invoicing currency.""" + threshold_total_amount_config: Required[Dict[str, object]] - currency: Optional[str] - """The currency of the price. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - If not provided, the currency of the plan will be used. + Only needed if the price is usage-based. """ - discount: Optional[PriceOverrideOverrideThresholdTotalAmountPriceDiscount] - """The subscription's override discount for the plan.""" + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + external_price_id: Optional[str] + """An alias for the price.""" -class PriceOverrideOverrideTieredPackagePriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. - For plan/plan phase discounts, this can be a subset of prices. + If unspecified, a single invoice is produced per billing cycle. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - This is a number between 0 and 1. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - - Number of usage units that this discount is for + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ -class PriceOverrideOverrideTieredPackagePrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - model_type: Required[Literal["tiered_package"]] + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - tiered_package_config: Required[Dict[str, object]] - conversion_rate: Optional[float] - """The per unit conversion rate of the price currency to the invoicing currency.""" +class AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - currency: Optional[str] - """The currency of the price. + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - If not provided, the currency of the plan will be used. - """ - discount: Optional[PriceOverrideOverrideTieredPackagePriceDiscount] - """The subscription's override discount for the plan.""" +class AddPricePriceNewSubscriptionTieredPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + item_id: Required[str] + """The id of the item the plan will be associated with.""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + model_type: Required[Literal["tiered_package"]] - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + name: Required[str] + """The name of the price.""" + tiered_package_config: Required[Dict[str, object]] -class PriceOverrideOverrideTieredWithMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + Only needed if the price is usage-based. + """ - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - For plan/plan phase discounts, this can be a subset of prices. + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - This is a number between 0 and 1. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + external_price_id: Optional[str] + """An alias for the price.""" - Number of usage units that this discount is for + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. """ + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" -class PriceOverrideOverrideTieredWithMinimumPrice(TypedDict, total=False): - id: Required[str] - - model_type: Required[Literal["tiered_with_minimum"]] + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - tiered_with_minimum_config: Required[Dict[str, object]] + If unspecified, a single invoice is produced per billing cycle. + """ - conversion_rate: Optional[float] - """The per unit conversion rate of the price currency to the invoicing currency.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - currency: Optional[str] - """The currency of the price. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - If not provided, the currency of the plan will be used. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - discount: Optional[PriceOverrideOverrideTieredWithMinimumPriceDiscount] - """The subscription's override discount for the plan.""" - fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" +class AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" +class AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" -class PriceOverrideOverridePackageWithAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. +class AddPricePriceNewSubscriptionTieredWithMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - For plan/plan phase discounts, this can be a subset of prices. - """ + item_id: Required[str] + """The id of the item the plan will be associated with.""" - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + model_type: Required[Literal["tiered_with_minimum"]] - This is a number between 0 and 1. - """ + name: Required[str] + """The name of the price.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + tiered_with_minimum_config: Required[Dict[str, object]] - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - Number of usage units that this discount is for + Only needed if the price is usage-based. """ + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ -class PriceOverrideOverridePackageWithAllocationPrice(TypedDict, total=False): - id: Required[str] - - model_type: Required[Literal["package_with_allocation"]] - - package_with_allocation_config: Required[Dict[str, object]] + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverridePackageWithAllocationPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. -class PriceOverrideOverrideUnitWithPercentPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + If unspecified, a single invoice is produced per billing cycle. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - For plan/plan phase discounts, this can be a subset of prices. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - This is a number between 0 and 1. - """ +class AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. - Number of usage units that this discount is for - """ +class AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideUnitWithPercentPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionUnitWithPercentPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" model_type: Required[Literal["unit_with_percent"]] + name: Required[str] + """The name of the price.""" + unit_with_percent_config: Required[Dict[str, object]] + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. - - If not provided, the currency of the plan will be used. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. """ - discount: Optional[PriceOverrideOverrideUnitWithPercentPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" - - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" - - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" -class PriceOverrideOverrideGroupedAllocationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + invoicing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + If unspecified, a single invoice is produced per billing cycle. + """ - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - For plan/plan phase discounts, this can be a subset of prices. + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. - - This is a number between 0 and 1. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. +class AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - Number of usage units that this discount is for - """ + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideGroupedAllocationPrice(TypedDict, total=False): - id: Required[str] +class AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" - grouped_allocation_config: Required[Dict[str, object]] + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" - model_type: Required[Literal["grouped_allocation"]] - conversion_rate: Optional[float] - """The per unit conversion rate of the price currency to the invoicing currency.""" +class AddPricePriceNewSubscriptionPackageWithAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - currency: Optional[str] - """The currency of the price. + item_id: Required[str] + """The id of the item the plan will be associated with.""" - If not provided, the currency of the plan will be used. - """ + model_type: Required[Literal["package_with_allocation"]] - discount: Optional[PriceOverrideOverrideGroupedAllocationPriceDiscount] - """The subscription's override discount for the plan.""" + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionTierWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] + + name: Required[str] + """The name of the price.""" + + tiered_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionUnitWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_allocation_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_with_prorated_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class AddPricePriceNewSubscriptionBulkWithProrationPrice(TypedDict, total=False): + bulk_with_proration_config: Required[Dict[str, object]] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk_with_proration"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[AddPricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + AddPricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +AddPricePrice: TypeAlias = Union[ + AddPricePriceNewSubscriptionUnitPrice, + AddPricePriceNewSubscriptionPackagePrice, + AddPricePriceNewSubscriptionMatrixPrice, + AddPricePriceNewSubscriptionTieredPrice, + AddPricePriceNewSubscriptionTieredBpsPrice, + AddPricePriceNewSubscriptionBpsPrice, + AddPricePriceNewSubscriptionBulkBpsPrice, + AddPricePriceNewSubscriptionBulkPrice, + AddPricePriceNewSubscriptionThresholdTotalAmountPrice, + AddPricePriceNewSubscriptionTieredPackagePrice, + AddPricePriceNewSubscriptionTieredWithMinimumPrice, + AddPricePriceNewSubscriptionUnitWithPercentPrice, + AddPricePriceNewSubscriptionPackageWithAllocationPrice, + AddPricePriceNewSubscriptionTierWithProrationPrice, + AddPricePriceNewSubscriptionUnitWithProrationPrice, + AddPricePriceNewSubscriptionGroupedAllocationPrice, + AddPricePriceNewSubscriptionGroupedWithProratedMinimumPrice, + AddPricePriceNewSubscriptionBulkWithProrationPrice, +] + + +class AddPrice(TypedDict, total=False): + discounts: Optional[Iterable[AddPriceDiscount]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for this price. + """ + + end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The end date of the price interval. + + This is the date that the price will stop billing on the subscription. If null, + billing will end when the phase or subscription ends. + """ + + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" + + maximum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for this price. + """ + + minimum_amount: Optional[str] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for this price. + """ + + plan_phase_order: Optional[int] + """The phase to add this price to.""" + + price: Optional[AddPricePrice] + """The definition of a new price to create and add to the subscription.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" + + start_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The start date of the price interval. + + This is the date that the price will start billing on the subscription. If null, + billing will start when the phase or subscription starts. + """ + + +class BillingCycleAnchorConfiguration(TypedDict, total=False): + day: Required[int] + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class RemoveAdjustment(TypedDict, total=False): + adjustment_id: Required[str] + """The id of the adjustment to remove on the subscription.""" + + +class RemovePrice(TypedDict, total=False): + external_price_id: Optional[str] + """The external price id of the price to remove on the subscription.""" + + price_id: Optional[str] + """The id of the price to remove on the subscription.""" + + +class ReplaceAdjustmentAdjustmentNewPercentageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["percentage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + percentage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewUsageDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["usage_discount"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + usage_discount: Required[float] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewAmountDiscount(TypedDict, total=False): + adjustment_type: Required[Literal["amount_discount"]] + + amount_discount: Required[str] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewMinimum(TypedDict, total=False): + adjustment_type: Required[Literal["minimum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + item_id: Required[str] + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +class ReplaceAdjustmentAdjustmentNewMaximum(TypedDict, total=False): + adjustment_type: Required[Literal["maximum"]] + + applies_to_price_ids: Required[List[str]] + """The set of price IDs to which this adjustment applies.""" + + maximum_amount: Required[str] + + is_invoice_level: bool + """When false, this adjustment will be applied to a single price. + + Otherwise, it will be applied at the invoice level, possibly to multiple prices. + """ + + +ReplaceAdjustmentAdjustment: TypeAlias = Union[ + ReplaceAdjustmentAdjustmentNewPercentageDiscount, + ReplaceAdjustmentAdjustmentNewUsageDiscount, + ReplaceAdjustmentAdjustmentNewAmountDiscount, + ReplaceAdjustmentAdjustmentNewMinimum, + ReplaceAdjustmentAdjustmentNewMaximum, +] + + +class ReplaceAdjustment(TypedDict, total=False): + adjustment: Required[ReplaceAdjustmentAdjustment] + """The definition of a new adjustment to create and add to the subscription.""" + + replaces_adjustment_id: Required[str] + """The id of the adjustment on the plan to replace in the subscription.""" + + +class ReplacePriceDiscount(TypedDict, total=False): + discount_type: Required[Literal["percentage", "usage", "amount"]] + + amount_discount: Optional[str] + """Only available if discount_type is `amount`.""" + + percentage_discount: Optional[float] + """Only available if discount_type is `percentage`. + + This is a number between 0 and 1. + """ + + usage_discount: Optional[float] + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +class ReplacePricePriceNewSubscriptionUnitPriceUnitConfig(TypedDict, total=False): + unit_amount: Required[str] + """Rate per unit of usage""" + + +class ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit"]] + + name: Required[str] + """The name of the price.""" + + unit_config: Required[ReplacePricePriceNewSubscriptionUnitPriceUnitConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionPackagePricePackageConfig(TypedDict, total=False): + package_amount: Required[str] + """A currency amount to rate usage by""" + + package_size: Required[int] + """An integer amount to represent package size. + + For example, 1000 here would divide usage by 1000 before multiplying by + package_amount in rating + """ + + +class ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["package"]] + + name: Required[str] + """The name of the price.""" + + package_config: Required[ReplacePricePriceNewSubscriptionPackagePricePackageConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionPackagePriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue(TypedDict, total=False): + dimension_values: Required[List[Optional[str]]] + """One or two matrix keys to filter usage to this Matrix value by. + + For example, ["region", "tier"] could be used to filter cloud usage by a cloud + region and an instance tier. + """ + + unit_amount: Required[str] + """Unit price for the specified dimension_values""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig(TypedDict, total=False): + default_unit_amount: Required[str] + """Default per unit rate for any usage not bucketed into a specified matrix_value""" + + dimensions: Required[List[Optional[str]]] + """One or two event property values to evaluate matrix groups by""" + + matrix_values: Required[Iterable[ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfigMatrixValue]] + """Matrix values for specified matrix grouping keys""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionMatrixPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + matrix_config: Required[ReplacePricePriceNewSubscriptionMatrixPriceMatrixConfig] + + model_type: Required[Literal["matrix"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionMatrixPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionMatrixPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier(TypedDict, total=False): + first_unit: Required[float] + """Inclusive tier starting value""" + + unit_amount: Required[str] + """Amount per unit""" + + last_unit: Optional[float] + """Exclusive tier ending value. If null, this is treated as the last tier""" + + +class ReplacePricePriceNewSubscriptionTieredPriceTieredConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredPriceTieredConfigTier]] + """Tiers for rating based on total usage quantities into the specified tier""" + + +class ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered"]] + + name: Required[str] + """The name of the price.""" + + tiered_config: Required[ReplacePricePriceNewSubscriptionTieredPriceTieredConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier(TypedDict, total=False): + bps: Required[float] + """Per-event basis point rate""" + + minimum_amount: Required[str] + """Inclusive tier starting value""" + + maximum_amount: Optional[str] + """Exclusive tier ending value""" + + per_unit_maximum: Optional[str] + """Per unit maximum to charge""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfigTier]] + """ + Tiers for a Graduated BPS pricing model, where usage is bucketed into specified + tiers + """ + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredBpsPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_bps"]] + + name: Required[str] + """The name of the price.""" + + tiered_bps_config: Required[ReplacePricePriceNewSubscriptionTieredBpsPriceTieredBpsConfig] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBpsPriceBpsConfig(TypedDict, total=False): + bps: Required[float] + """Basis point take rate per event""" + + per_unit_maximum: Optional[str] + """Optional currency amount maximum to cap spend per event""" + + +class ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBpsPrice(TypedDict, total=False): + bps_config: Required[ReplacePricePriceNewSubscriptionBpsPriceBpsConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bps"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier(TypedDict, total=False): + bps: Required[float] + """Basis points to rate on""" + + maximum_amount: Optional[str] + """Upper bound for tier""" + + per_unit_maximum: Optional[str] + """The maximum amount to charge for any one event""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfigTier]] + """ + Tiers for a bulk BPS pricing model where all usage is aggregated to a single + tier based on total volume + """ + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkBpsPrice(TypedDict, total=False): + bulk_bps_config: Required[ReplacePricePriceNewSubscriptionBulkBpsPriceBulkBpsConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk_bps"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkBpsPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkBpsPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier(TypedDict, total=False): + unit_amount: Required[str] + """Amount per unit""" + + maximum_units: Optional[float] + """Upper bound for this tier""" + + +class ReplacePricePriceNewSubscriptionBulkPriceBulkConfig(TypedDict, total=False): + tiers: Required[Iterable[ReplacePricePriceNewSubscriptionBulkPriceBulkConfigTier]] + """Bulk tiers for rating based on total usage volume""" + + +class ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkPrice(TypedDict, total=False): + bulk_config: Required[ReplacePricePriceNewSubscriptionBulkPriceBulkConfig] + + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["bulk"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionBulkPriceInvoicingCycleConfiguration] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["threshold_total_amount"]] + + name: Required[str] + """The name of the price.""" + + threshold_total_amount_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionThresholdTotalAmountPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredPackagePrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_package"]] + + name: Required[str] + """The name of the price.""" + + tiered_package_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionTieredPackagePriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredPackagePriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTieredWithMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_minimum"]] + + name: Required[str] + """The name of the price.""" + + tiered_with_minimum_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredWithMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTieredWithMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithPercentPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_percent"]] + + name: Required[str] + """The name of the price.""" + + unit_with_percent_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ReplacePricePriceNewSubscriptionUnitWithPercentPriceBillingCycleConfiguration] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithPercentPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionPackageWithAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["package_with_allocation"]] + + name: Required[str] + """The name of the price.""" + + package_with_allocation_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionPackageWithAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionPackageWithAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. -class PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionTierWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["tiered_with_proration"]] - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + name: Required[str] + """The name of the price.""" - For plan/plan phase discounts, this can be a subset of prices. + tiered_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - This is a number between 0 and 1. + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTierWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - Number of usage units that this discount is for + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. """ + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" -class PriceOverrideOverrideGroupedWithProratedMinimumPrice(TypedDict, total=False): - id: Required[str] + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionTierWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. - grouped_with_prorated_minimum_config: Required[Dict[str, object]] + If unspecified, a single invoice is produced per billing cycle. + """ - model_type: Required[Literal["grouped_with_prorated_minimum"]] + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionUnitWithProrationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["unit_with_proration"]] + + name: Required[str] + """The name of the price.""" + + unit_with_proration_config: Required[Dict[str, object]] + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionUnitWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionGroupedAllocationPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + grouped_allocation_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_allocation"]] + + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. - If not provided, the currency of the plan will be used. + Only needed if the price is usage-based. """ - discount: Optional[PriceOverrideOverrideGroupedWithProratedMinimumPriceDiscount] - """The subscription's override discount for the plan.""" + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedAllocationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" + + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ - maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" - minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedAllocationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + If unspecified, a single invoice is produced per billing cycle. + """ -class PriceOverrideOverrideBulkWithProrationPriceDiscount(TypedDict, total=False): - discount_type: Required[Literal["percentage", "trial", "usage", "amount"]] + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. - amount_discount: Optional[str] - """Only available if discount_type is `amount`.""" + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration( + TypedDict, total=False +): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice(TypedDict, total=False): + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" - applies_to_price_ids: Optional[List[str]] - """List of price_ids that this discount applies to. + grouped_with_prorated_minimum_config: Required[Dict[str, object]] + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + + model_type: Required[Literal["grouped_with_prorated_minimum"]] - For plan/plan phase discounts, this can be a subset of prices. + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. """ - percentage_discount: Optional[float] - """Only available if discount_type is `percentage`. + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ - This is a number between 0 and 1. + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. """ - trial_amount_discount: Optional[str] - """Only available if discount_type is `trial`""" + conversion_rate: Optional[float] + """The per unit conversion rate of the price currency to the invoicing currency.""" - usage_discount: Optional[float] - """Only available if discount_type is `usage`. + currency: Optional[str] + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ - Number of usage units that this discount is for + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ + + reference_id: Optional[str] """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +class ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" -class PriceOverrideOverrideBulkWithProrationPrice(TypedDict, total=False): - id: Required[str] +class ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration(TypedDict, total=False): + duration: Required[int] + """The duration of the billing period.""" + duration_unit: Required[Literal["day", "month"]] + """The unit of billing period duration.""" + + +class ReplacePricePriceNewSubscriptionBulkWithProrationPrice(TypedDict, total=False): bulk_with_proration_config: Required[Dict[str, object]] + cadence: Required[Literal["annual", "semi_annual", "monthly", "quarterly", "one_time", "custom"]] + """The cadence to bill for this price on.""" + + item_id: Required[str] + """The id of the item the plan will be associated with.""" + model_type: Required[Literal["bulk_with_proration"]] + name: Required[str] + """The name of the price.""" + + billable_metric_id: Optional[str] + """The id of the billable metric for the price. + + Only needed if the price is usage-based. + """ + + billed_in_advance: Optional[bool] + """ + If the Price represents a fixed cost, the price will be billed in-advance if + this is true, and in-arrears if this is false. + """ + + billing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionBulkWithProrationPriceBillingCycleConfiguration + ] + """ + For custom cadence: specifies the duration of the billing period in days or + months. + """ + conversion_rate: Optional[float] """The per unit conversion rate of the price currency to the invoicing currency.""" currency: Optional[str] - """The currency of the price. + """ + An ISO 4217 currency string, or custom pricing unit identifier, in which this + price is billed. + """ + + external_price_id: Optional[str] + """An alias for the price.""" + + fixed_price_quantity: Optional[float] + """ + If the Price represents a fixed cost, this represents the quantity of units + applied. + """ + + invoice_grouping_key: Optional[str] + """The property used to group this price on an invoice""" + + invoicing_cycle_configuration: Optional[ + ReplacePricePriceNewSubscriptionBulkWithProrationPriceInvoicingCycleConfiguration + ] + """Within each billing cycle, specifies the cadence at which invoices are produced. + + If unspecified, a single invoice is produced per billing cycle. + """ + + metadata: Optional[Dict[str, Optional[str]]] + """User-specified key/value pairs for the resource. + + Individual keys can be removed by setting the value to `null`, and the entire + metadata mapping can be cleared by setting `metadata` to `null`. + """ - If not provided, the currency of the plan will be used. + reference_id: Optional[str] + """ + A transient ID that can be used to reference this price when adding adjustments + in the same API call. + """ + + +ReplacePricePrice: TypeAlias = Union[ + ReplacePricePriceNewSubscriptionUnitPrice, + ReplacePricePriceNewSubscriptionPackagePrice, + ReplacePricePriceNewSubscriptionMatrixPrice, + ReplacePricePriceNewSubscriptionTieredPrice, + ReplacePricePriceNewSubscriptionTieredBpsPrice, + ReplacePricePriceNewSubscriptionBpsPrice, + ReplacePricePriceNewSubscriptionBulkBpsPrice, + ReplacePricePriceNewSubscriptionBulkPrice, + ReplacePricePriceNewSubscriptionThresholdTotalAmountPrice, + ReplacePricePriceNewSubscriptionTieredPackagePrice, + ReplacePricePriceNewSubscriptionTieredWithMinimumPrice, + ReplacePricePriceNewSubscriptionUnitWithPercentPrice, + ReplacePricePriceNewSubscriptionPackageWithAllocationPrice, + ReplacePricePriceNewSubscriptionTierWithProrationPrice, + ReplacePricePriceNewSubscriptionUnitWithProrationPrice, + ReplacePricePriceNewSubscriptionGroupedAllocationPrice, + ReplacePricePriceNewSubscriptionGroupedWithProratedMinimumPrice, + ReplacePricePriceNewSubscriptionBulkWithProrationPrice, +] + + +class ReplacePrice(TypedDict, total=False): + replaces_price_id: Required[str] + """The id of the price on the plan to replace in the subscription.""" + + discounts: Optional[Iterable[ReplacePriceDiscount]] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's discounts for the replacement price. """ - discount: Optional[PriceOverrideOverrideBulkWithProrationPriceDiscount] - """The subscription's override discount for the plan.""" + external_price_id: Optional[str] + """The external price id of the price to add to the subscription.""" fixed_price_quantity: Optional[float] - """The starting quantity of the price, if the price is a fixed price.""" + """The new quantity of the price, if the price is a fixed price.""" maximum_amount: Optional[str] - """The subscription's override maximum amount for the plan.""" + """[DEPRECATED] Use add_adjustments instead. + + The subscription's maximum amount for the replacement price. + """ minimum_amount: Optional[str] - """The subscription's override minimum amount for the plan.""" - - -PriceOverride: TypeAlias = Union[ - PriceOverrideOverrideUnitPrice, - PriceOverrideOverridePackagePrice, - PriceOverrideOverrideMatrixPrice, - PriceOverrideOverrideTieredPrice, - PriceOverrideOverrideTieredBpsPrice, - PriceOverrideOverrideBpsPrice, - PriceOverrideOverrideBulkBpsPrice, - PriceOverrideOverrideBulkPrice, - PriceOverrideOverrideThresholdTotalAmountPrice, - PriceOverrideOverrideTieredPackagePrice, - PriceOverrideOverrideTieredWithMinimumPrice, - PriceOverrideOverridePackageWithAllocationPrice, - PriceOverrideOverrideUnitWithPercentPrice, - PriceOverrideOverrideGroupedAllocationPrice, - PriceOverrideOverrideGroupedWithProratedMinimumPrice, - PriceOverrideOverrideBulkWithProrationPrice, -] + """[DEPRECATED] Use add_adjustments instead. + + The subscription's minimum amount for the replacement price. + """ + + price: Optional[ReplacePricePrice] + """The definition of a new price to create and add to the subscription.""" + + price_id: Optional[str] + """The id of the price to add to the subscription.""" diff --git a/src/orb/types/subscription_schedule_plan_change_response.py b/src/orb/types/subscription_schedule_plan_change_response.py new file mode 100644 index 00000000..01cae797 --- /dev/null +++ b/src/orb/types/subscription_schedule_plan_change_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionSchedulePlanChangeResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionSchedulePlanChangeResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_trigger_phase_response.py b/src/orb/types/subscription_trigger_phase_response.py new file mode 100644 index 00000000..46c4e437 --- /dev/null +++ b/src/orb/types/subscription_trigger_phase_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionTriggerPhaseResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionTriggerPhaseResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_unschedule_cancellation_response.py b/src/orb/types/subscription_unschedule_cancellation_response.py new file mode 100644 index 00000000..d8642ac4 --- /dev/null +++ b/src/orb/types/subscription_unschedule_cancellation_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionUnscheduleCancellationResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionUnscheduleCancellationResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_unschedule_fixed_fee_quantity_updates_response.py b/src/orb/types/subscription_unschedule_fixed_fee_quantity_updates_response.py new file mode 100644 index 00000000..28d2b6aa --- /dev/null +++ b/src/orb/types/subscription_unschedule_fixed_fee_quantity_updates_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_unschedule_pending_plan_changes_response.py b/src/orb/types/subscription_unschedule_pending_plan_changes_response.py new file mode 100644 index 00000000..3b4bfd32 --- /dev/null +++ b/src/orb/types/subscription_unschedule_pending_plan_changes_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionUnschedulePendingPlanChangesResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionUnschedulePendingPlanChangesResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_update_fixed_fee_quantity_response.py b/src/orb/types/subscription_update_fixed_fee_quantity_response.py new file mode 100644 index 00000000..55a83b5e --- /dev/null +++ b/src/orb/types/subscription_update_fixed_fee_quantity_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionUpdateFixedFeeQuantityResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionUpdateFixedFeeQuantityResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/subscription_update_trial_params.py b/src/orb/types/subscription_update_trial_params.py new file mode 100644 index 00000000..03481252 --- /dev/null +++ b/src/orb/types/subscription_update_trial_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["SubscriptionUpdateTrialParams"] + + +class SubscriptionUpdateTrialParams(TypedDict, total=False): + trial_end_date: Required[ + Annotated[Union[Union[str, datetime], Literal["immediate"]], PropertyInfo(format="iso8601")] + ] + """ + The new date that the trial should end, or the literal string `immediate` to end + the trial immediately. + """ + + shift: bool + """ + If true, shifts subsequent price and adjustment intervals (preserving their + durations, but adjusting their absolute dates). + """ diff --git a/src/orb/types/subscription_update_trial_response.py b/src/orb/types/subscription_update_trial_response.py new file mode 100644 index 00000000..c2b6797b --- /dev/null +++ b/src/orb/types/subscription_update_trial_response.py @@ -0,0 +1,768 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .plan import Plan +from .price import Price +from .._utils import PropertyInfo +from .._models import BaseModel +from .customer import Customer + +__all__ = [ + "SubscriptionUpdateTrialResponse", + "AdjustmentInterval", + "AdjustmentIntervalAdjustment", + "AdjustmentIntervalAdjustmentAmountDiscountAdjustment", + "AdjustmentIntervalAdjustmentPercentageDiscountAdjustment", + "AdjustmentIntervalAdjustmentUsageDiscountAdjustment", + "AdjustmentIntervalAdjustmentMinimumAdjustment", + "AdjustmentIntervalAdjustmentMaximumAdjustment", + "BillingCycleAnchorConfiguration", + "DiscountInterval", + "DiscountIntervalAmountDiscountInterval", + "DiscountIntervalPercentageDiscountInterval", + "DiscountIntervalUsageDiscountInterval", + "FixedFeeQuantitySchedule", + "MaximumInterval", + "MinimumInterval", + "PriceInterval", + "PriceIntervalFixedFeeQuantityTransition", + "RedeemedCoupon", + "TrialInfo", +] + + +class AdjustmentIntervalAdjustmentAmountDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["amount_discount"] + + amount_discount: str + """ + The amount by which to discount the prices this adjustment applies to in a given + billing period. + """ + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentPercentageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["percentage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + percentage_discount: float + """ + The percentage (as a value between 0 and 1) by which to discount the price + intervals this adjustment applies to in a given billing period. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentUsageDiscountAdjustment(BaseModel): + id: str + + adjustment_type: Literal["usage_discount"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + usage_discount: float + """ + The number of usage units by which to discount the price this adjustment applies + to in a given billing period. + """ + + +class AdjustmentIntervalAdjustmentMinimumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["minimum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + item_id: str + """The item ID that revenue from this minimum will be attributed to.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +class AdjustmentIntervalAdjustmentMaximumAdjustment(BaseModel): + id: str + + adjustment_type: Literal["maximum"] + + applies_to_price_ids: List[str] + """The price IDs that this adjustment applies to.""" + + is_invoice_level: bool + """ + True for adjustments that apply to an entire invocice, false for adjustments + that apply to only one price. + """ + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the prices this + adjustment applies to. + """ + + plan_phase_order: Optional[int] = None + """The plan phase in which this adjustment is active.""" + + reason: Optional[str] = None + """The reason for the adjustment.""" + + +AdjustmentIntervalAdjustment: TypeAlias = Annotated[ + Union[ + AdjustmentIntervalAdjustmentAmountDiscountAdjustment, + AdjustmentIntervalAdjustmentPercentageDiscountAdjustment, + AdjustmentIntervalAdjustmentUsageDiscountAdjustment, + AdjustmentIntervalAdjustmentMinimumAdjustment, + AdjustmentIntervalAdjustmentMaximumAdjustment, + ], + PropertyInfo(discriminator="adjustment_type"), +] + + +class AdjustmentInterval(BaseModel): + id: str + + adjustment: AdjustmentIntervalAdjustment + + applies_to_price_interval_ids: List[str] + """The price interval IDs that this adjustment applies to.""" + + end_date: Optional[datetime] = None + """The end date of the adjustment interval.""" + + start_date: datetime + """The start date of the adjustment interval.""" + + +class BillingCycleAnchorConfiguration(BaseModel): + day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + month: Optional[int] = None + """The month on which the billing cycle is anchored (e.g. + + a quarterly price anchored in February would have cycles starting February, May, + August, and November). + """ + + year: Optional[int] = None + """The year on which the billing cycle is anchored (e.g. + + a 2 year billing cycle anchored on 2021 would have cycles starting on 2021, + 2023, 2025, etc.). + """ + + +class DiscountIntervalAmountDiscountInterval(BaseModel): + amount_discount: str + """Only available if discount_type is `amount`.""" + + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["amount"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalPercentageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["percentage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + percentage_discount: float + """ + Only available if discount_type is `percentage`.This is a number between 0 + and 1. + """ + + start_date: datetime + """The start date of the discount interval.""" + + +class DiscountIntervalUsageDiscountInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this discount interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this discount interval applies to.""" + + discount_type: Literal["usage"] + + end_date: Optional[datetime] = None + """The end date of the discount interval.""" + + start_date: datetime + """The start date of the discount interval.""" + + usage_discount: float + """Only available if discount_type is `usage`. + + Number of usage units that this discount is for + """ + + +DiscountInterval: TypeAlias = Annotated[ + Union[ + DiscountIntervalAmountDiscountInterval, + DiscountIntervalPercentageDiscountInterval, + DiscountIntervalUsageDiscountInterval, + ], + PropertyInfo(discriminator="discount_type"), +] + + +class FixedFeeQuantitySchedule(BaseModel): + end_date: Optional[datetime] = None + + price_id: str + + quantity: float + + start_date: datetime + + +class MaximumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this maximum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this maximum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the maximum interval.""" + + maximum_amount: str + """ + The maximum amount to charge in a given billing period for the price intervals + this transform applies to. + """ + + start_date: datetime + """The start date of the maximum interval.""" + + +class MinimumInterval(BaseModel): + applies_to_price_ids: List[str] + """The price ids that this minimum interval applies to.""" + + applies_to_price_interval_ids: List[str] + """The price interval ids that this minimum interval applies to.""" + + end_date: Optional[datetime] = None + """The end date of the minimum interval.""" + + minimum_amount: str + """ + The minimum amount to charge in a given billing period for the price intervals + this minimum applies to. + """ + + start_date: datetime + """The start date of the minimum interval.""" + + +class PriceIntervalFixedFeeQuantityTransition(BaseModel): + effective_date: datetime + + price_id: str + + quantity: int + + +class PriceInterval(BaseModel): + id: str + + billing_cycle_day: int + """The day of the month that Orb bills for this price""" + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is exactly the + end of the billing period. Set to null if this price interval is not currently + active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if this price interval is not currently active. + """ + + end_date: Optional[datetime] = None + """The end date of the price interval. + + This is the date that Orb stops billing for this price. + """ + + fixed_fee_quantity_transitions: Optional[List[PriceIntervalFixedFeeQuantityTransition]] = None + """The fixed fee quantity transitions for this price interval. + + This is only relevant for fixed fees. + """ + + price: Price + """ + The Price resource represents a price that can be billed on a subscription, + resulting in a charge on an invoice in the form of an invoice line item. Prices + take a quantity and determine an amount to bill. + + Orb supports a few different pricing models out of the box. Each of these models + is serialized differently in a given Price object. The model_type field + determines the key for the configuration object that is present. + + ## Unit pricing + + With unit pricing, each unit costs a fixed amount. + + ```json + { + ... + "model_type": "unit", + "unit_config": { + "unit_amount": "0.50" + } + ... + } + ``` + + ## Tiered pricing + + In tiered pricing, the cost of a given unit depends on the tier range that it + falls into, where each tier range is defined by an upper and lower bound. For + example, the first ten units may cost $0.50 each and all units thereafter may + cost $0.10 each. + + ```json + { + ... + "model_type": "tiered", + "tiered_config": { + "tiers": [ + { + "first_unit": 1, + "last_unit": 10, + "unit_amount": "0.50" + }, + { + "first_unit": 11, + "last_unit": null, + "unit_amount": "0.10" + } + ] + } + ... + ``` + + ## Bulk pricing + + Bulk pricing applies when the number of units determine the cost of all units. + For example, if you've bought less than 10 units, they may each be $0.50 for a + total of $5.00. Once you've bought more than 10 units, all units may now be + priced at $0.40 (i.e. 101 units total would be $40.40). + + ```json + { + ... + "model_type": "bulk", + "bulk_config": { + "tiers": [ + { + "maximum_units": 10, + "unit_amount": "0.50" + }, + { + "maximum_units": 1000, + "unit_amount": "0.40" + } + ] + } + ... + } + ``` + + ## Package pricing + + Package pricing defines the size or granularity of a unit for billing purposes. + For example, if the package size is set to 5, then 4 units will be billed as 5 + and 6 units will be billed at 10. + + ```json + { + ... + "model_type": "package", + "package_config": { + "package_amount": "0.80", + "package_size": 10 + } + ... + } + ``` + + ## BPS pricing + + BPS pricing specifies a per-event (e.g. per-payment) rate in one hundredth of a + percent (the number of basis points to charge), as well as a cap per event to + assess. For example, this would allow you to assess a fee of 0.25% on every + payment you process, with a maximum charge of $25 per payment. + + ```json + { + ... + "model_type": "bps", + "bps_config": { + "bps": 125, + "per_unit_maximum": "11.00" + } + ... + } + ``` + + ## Bulk BPS pricing + + Bulk BPS pricing specifies BPS parameters in a tiered manner, dependent on the + total quantity across all events. Similar to bulk pricing, the BPS parameters of + a given event depends on the tier range that the billing period falls into. Each + tier range is defined by an upper bound. For example, after $1.5M of payment + volume is reached, each individual payment may have a lower cap or a smaller + take-rate. + + ```json + ... + "model_type": "bulk_bps", + "bulk_bps_config": { + "tiers": [ + { + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Tiered BPS pricing + + Tiered BPS pricing specifies BPS parameters in a graduated manner, where an + event's applicable parameter is a function of its marginal addition to the + period total. Similar to tiered pricing, the BPS parameters of a given event + depends on the tier range that it falls into, where each tier range is defined + by an upper and lower bound. For example, the first few payments may have a 0.8 + BPS take-rate and all payments after a specific volume may incur a take-rate of + 0.5 BPS each. + + ```json + ... + "model_type": "tiered_bps", + "tiered_bps_config": { + "tiers": [ + { + "minimum_amount": "0", + "maximum_amount": "1000000.00", + "bps": 125, + "per_unit_maximum": "19.00" + }, + { + "minimum_amount": "1000000.00", + "maximum_amount": null, + "bps": 115, + "per_unit_maximum": "4.00" + } + ] + } + ... + } + ``` + + ## Matrix pricing + + Matrix pricing defines a set of unit prices in a one or two-dimensional matrix. + `dimensions` defines the two event property values evaluated in this pricing + model. In a one-dimensional matrix, the second value is `null`. Every + configuration has a list of `matrix_values` which give the unit prices for + specified property values. In a one-dimensional matrix, the matrix values will + have `dimension_values` where the second value of the pair is null. If an event + does not match any of the dimension values in the matrix, it will resort to the + `default_unit_amount`. + + ```json + { + "model_type": "matrix" + "matrix_config": { + "default_unit_amount": "3.00", + "dimensions": [ + "cluster_name", + "region" + ], + "matrix_values": [ + { + "dimension_values": [ + "alpha", + "west" + ], + "unit_amount": "2.00" + }, + ... + ] + } + } + ``` + + ## Fixed fees + + Fixed fees are prices that are applied independent of usage quantities, and + follow unit pricing. They also have an additional parameter + `fixed_price_quantity`. If the Price represents a fixed cost, this represents + the quantity of units applied. + + ```json + { + ... + "id": "price_id", + "model_type": "unit", + "unit_config": { + "unit_amount": "2.00" + }, + "fixed_price_quantity": 3.0 + ... + } + ``` + """ + + start_date: datetime + """The start date of the price interval. + + This is the date that Orb starts billing for this price. + """ + + +class RedeemedCoupon(BaseModel): + coupon_id: str + + end_date: Optional[datetime] = None + + start_date: datetime + + +class TrialInfo(BaseModel): + end_date: Optional[datetime] = None + + +class SubscriptionUpdateTrialResponse(BaseModel): + id: str + + active_plan_phase_order: Optional[int] = None + """ + The current plan phase that is active, only if the subscription's plan has + phases. + """ + + adjustment_intervals: List[AdjustmentInterval] + """The adjustment intervals for this subscription.""" + + auto_collection: Optional[bool] = None + """ + Determines whether issued invoices for this subscription will automatically be + charged with the saved payment method on the due date. This property defaults to + the plan's behavior. If null, defaults to the customer's setting. + """ + + billing_cycle_anchor_configuration: BillingCycleAnchorConfiguration + + billing_cycle_day: int + """The day of the month on which the billing cycle is anchored. + + If the maximum number of days in a month is greater than this value, the last + day of the month is the billing cycle day (e.g. billing_cycle_day=31 for April + means the billing period begins on the 30th. + """ + + created_at: datetime + + current_billing_period_end_date: Optional[datetime] = None + """The end of the current billing period. + + This is an exclusive timestamp, such that the instant returned is not part of + the billing period. Set to null for subscriptions that are not currently active. + """ + + current_billing_period_start_date: Optional[datetime] = None + """The start date of the current billing period. + + This is an inclusive timestamp; the instant returned is exactly the beginning of + the billing period. Set to null if the subscription is not currently active. + """ + + customer: Customer + """ + A customer is a buyer of your products, and the other party to the billing + relationship. + + In Orb, customers are assigned system generated identifiers automatically, but + it's often desirable to have these match existing identifiers in your system. To + avoid having to denormalize Orb ID information, you can pass in an + `external_customer_id` with your own identifier. See + [Customer ID Aliases](../guides/events-and-metrics/customer-aliases) for further + information about how these aliases work in Orb. + + In addition to having an identifier in your system, a customer may exist in a + payment provider solution like Stripe. Use the `payment_provider_id` and the + `payment_provider` enum field to express this mapping. + + A customer also has a timezone (from the standard + [IANA timezone database](https://www.iana.org/time-zones)), which defaults to + your account's timezone. See + [Timezone localization](../guides/product-catalog/timezones.md) for information + on what this timezone parameter influences within Orb. + """ + + default_invoice_memo: Optional[str] = None + """Determines the default memo on this subscriptions' invoices. + + Note that if this is not provided, it is determined by the plan configuration. + """ + + discount_intervals: List[DiscountInterval] + """The discount intervals for this subscription.""" + + end_date: Optional[datetime] = None + """The date Orb stops billing for this subscription.""" + + fixed_fee_quantity_schedule: List[FixedFeeQuantitySchedule] + + invoicing_threshold: Optional[str] = None + + maximum_intervals: List[MaximumInterval] + """The maximum intervals for this subscription.""" + + metadata: Dict[str, str] + """User specified key-value pairs for the resource. + + If not present, this defaults to an empty dictionary. Individual keys can be + removed by setting the value to `null`, and the entire metadata mapping can be + cleared by setting `metadata` to `null`. + """ + + minimum_intervals: List[MinimumInterval] + """The minimum intervals for this subscription.""" + + net_terms: int + """ + Determines the difference between the invoice issue date for subscription + invoices as the date that they are due. A value of `0` here represents that the + invoice is due on issue, whereas a value of `30` represents that the customer + has a month to pay the invoice. + """ + + plan: Plan + """ + The [Plan](../guides/core-concepts.mdx#plan-and-price) resource represents a + plan that can be subscribed to by a customer. Plans define the billing behavior + of the subscription. You can see more about how to configure prices in the + [Price resource](/reference/price). + """ + + price_intervals: List[PriceInterval] + """The price intervals for this subscription.""" + + redeemed_coupon: Optional[RedeemedCoupon] = None + + start_date: datetime + """The date Orb starts billing for this subscription.""" + + status: Literal["active", "ended", "upcoming"] + + trial_info: TrialInfo diff --git a/src/orb/types/top_level_ping_response.py b/src/orb/types/top_level_ping_response.py index 43ce3b3c..b7ab100c 100644 --- a/src/orb/types/top_level_ping_response.py +++ b/src/orb/types/top_level_ping_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["TopLevelPingResponse"] diff --git a/tests/api_resources/events/test_volume.py b/tests/api_resources/events/test_volume.py new file mode 100644 index 00000000..7de82b57 --- /dev/null +++ b/tests/api_resources/events/test_volume.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from orb import Orb, AsyncOrb +from orb._utils import parse_datetime +from tests.utils import assert_matches_type +from orb.types.events import EventVolumes + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVolume: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: Orb) -> None: + volume = client.events.volume.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Orb) -> None: + volume = client.events.volume.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + cursor="cursor", + limit=1, + timeframe_end=parse_datetime("2024-10-11T06:00:00Z"), + ) + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Orb) -> None: + response = client.events.volume.with_raw_response.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Orb) -> None: + with client.events.volume.with_streaming_response.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = response.parse() + assert_matches_type(EventVolumes, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncVolume: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_list(self, async_client: AsyncOrb) -> None: + volume = await async_client.events.volume.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None: + volume = await async_client.events.volume.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + cursor="cursor", + limit=1, + timeframe_end=parse_datetime("2024-10-11T06:00:00Z"), + ) + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOrb) -> None: + response = await async_client.events.volume.with_raw_response.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + volume = response.parse() + assert_matches_type(EventVolumes, volume, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOrb) -> None: + async with async_client.events.volume.with_streaming_response.list( + timeframe_start=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + volume = await response.parse() + assert_matches_type(EventVolumes, volume, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_alerts.py b/tests/api_resources/test_alerts.py index 89ab0f66..cb07e015 100644 --- a/tests/api_resources/test_alerts.py +++ b/tests/api_resources/test_alerts.py @@ -63,7 +63,7 @@ def test_path_params_retrieve(self, client: Orb) -> None: def test_method_update(self, client: Orb) -> None: alert = client.alerts.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -71,7 +71,7 @@ def test_method_update(self, client: Orb) -> None: def test_raw_response_update(self, client: Orb) -> None: response = client.alerts.with_raw_response.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert response.is_closed is True @@ -83,7 +83,7 @@ def test_raw_response_update(self, client: Orb) -> None: def test_streaming_response_update(self, client: Orb) -> None: with client.alerts.with_streaming_response.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -100,7 +100,7 @@ def test_path_params_update(self, client: Orb) -> None: ): client.alerts.with_raw_response.update( alert_configuration_id="", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) @pytest.mark.skip(reason="plan_version=0 breaks Prism") @@ -162,7 +162,7 @@ def test_method_create_for_customer_with_all_params(self, client: Orb) -> None: customer_id="customer_id", currency="currency", type="usage_exceeded", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -218,7 +218,7 @@ def test_method_create_for_external_customer_with_all_params(self, client: Orb) external_customer_id="external_customer_id", currency="currency", type="usage_exceeded", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -263,7 +263,7 @@ def test_path_params_create_for_external_customer(self, client: Orb) -> None: def test_method_create_for_subscription(self, client: Orb) -> None: alert = client.alerts.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) assert_matches_type(Alert, alert, path=["response"]) @@ -272,7 +272,7 @@ def test_method_create_for_subscription(self, client: Orb) -> None: def test_method_create_for_subscription_with_all_params(self, client: Orb) -> None: alert = client.alerts.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", metric_id="metric_id", ) @@ -282,7 +282,7 @@ def test_method_create_for_subscription_with_all_params(self, client: Orb) -> No def test_raw_response_create_for_subscription(self, client: Orb) -> None: response = client.alerts.with_raw_response.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) @@ -295,7 +295,7 @@ def test_raw_response_create_for_subscription(self, client: Orb) -> None: def test_streaming_response_create_for_subscription(self, client: Orb) -> None: with client.alerts.with_streaming_response.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) as response: assert not response.is_closed @@ -311,7 +311,7 @@ def test_path_params_create_for_subscription(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): client.alerts.with_raw_response.create_for_subscription( subscription_id="", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) @@ -441,7 +441,7 @@ async def test_path_params_retrieve(self, async_client: AsyncOrb) -> None: async def test_method_update(self, async_client: AsyncOrb) -> None: alert = await async_client.alerts.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -449,7 +449,7 @@ async def test_method_update(self, async_client: AsyncOrb) -> None: async def test_raw_response_update(self, async_client: AsyncOrb) -> None: response = await async_client.alerts.with_raw_response.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert response.is_closed is True @@ -461,7 +461,7 @@ async def test_raw_response_update(self, async_client: AsyncOrb) -> None: async def test_streaming_response_update(self, async_client: AsyncOrb) -> None: async with async_client.alerts.with_streaming_response.update( alert_configuration_id="alert_configuration_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -478,7 +478,7 @@ async def test_path_params_update(self, async_client: AsyncOrb) -> None: ): await async_client.alerts.with_raw_response.update( alert_configuration_id="", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) @pytest.mark.skip(reason="plan_version=0 breaks Prism") @@ -540,7 +540,7 @@ async def test_method_create_for_customer_with_all_params(self, async_client: As customer_id="customer_id", currency="currency", type="usage_exceeded", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -596,7 +596,7 @@ async def test_method_create_for_external_customer_with_all_params(self, async_c external_customer_id="external_customer_id", currency="currency", type="usage_exceeded", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], ) assert_matches_type(Alert, alert, path=["response"]) @@ -641,7 +641,7 @@ async def test_path_params_create_for_external_customer(self, async_client: Asyn async def test_method_create_for_subscription(self, async_client: AsyncOrb) -> None: alert = await async_client.alerts.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) assert_matches_type(Alert, alert, path=["response"]) @@ -650,7 +650,7 @@ async def test_method_create_for_subscription(self, async_client: AsyncOrb) -> N async def test_method_create_for_subscription_with_all_params(self, async_client: AsyncOrb) -> None: alert = await async_client.alerts.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", metric_id="metric_id", ) @@ -660,7 +660,7 @@ async def test_method_create_for_subscription_with_all_params(self, async_client async def test_raw_response_create_for_subscription(self, async_client: AsyncOrb) -> None: response = await async_client.alerts.with_raw_response.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) @@ -673,7 +673,7 @@ async def test_raw_response_create_for_subscription(self, async_client: AsyncOrb async def test_streaming_response_create_for_subscription(self, async_client: AsyncOrb) -> None: async with async_client.alerts.with_streaming_response.create_for_subscription( subscription_id="subscription_id", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) as response: assert not response.is_closed @@ -689,7 +689,7 @@ async def test_path_params_create_for_subscription(self, async_client: AsyncOrb) with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): await async_client.alerts.with_raw_response.create_for_subscription( subscription_id="", - thresholds=[{"value": 0}, {"value": 0}, {"value": 0}], + thresholds=[{"value": 0}], type="usage_exceeded", ) diff --git a/tests/api_resources/test_credit_notes.py b/tests/api_resources/test_credit_notes.py index b44d927f..08d07146 100644 --- a/tests/api_resources/test_credit_notes.py +++ b/tests/api_resources/test_credit_notes.py @@ -18,6 +18,66 @@ class TestCreditNotes: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_create(self, client: Orb) -> None: + credit_note = client.credit_notes.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Orb) -> None: + credit_note = client.credit_notes.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + memo="An optional memo for my credit note.", + reason="duplicate", + ) + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Orb) -> None: + response = client.credit_notes.with_raw_response.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_note = response.parse() + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Orb) -> None: + with client.credit_notes.with_streaming_response.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_note = response.parse() + assert_matches_type(CreditNote, credit_note, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_list(self, client: Orb) -> None: credit_note = client.credit_notes.list() @@ -93,6 +153,66 @@ def test_path_params_fetch(self, client: Orb) -> None: class TestAsyncCreditNotes: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + async def test_method_create(self, async_client: AsyncOrb) -> None: + credit_note = await async_client.credit_notes.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: + credit_note = await async_client.credit_notes.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + memo="An optional memo for my credit note.", + reason="duplicate", + ) + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOrb) -> None: + response = await async_client.credit_notes.with_raw_response.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + credit_note = response.parse() + assert_matches_type(CreditNote, credit_note, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: + async with async_client.credit_notes.with_streaming_response.create( + line_items=[ + { + "amount": "amount", + "invoice_line_item_id": "4khy3nwzktxv7", + } + ], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + credit_note = await response.parse() + assert_matches_type(CreditNote, credit_note, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize async def test_method_list(self, async_client: AsyncOrb) -> None: credit_note = await async_client.credit_notes.list() diff --git a/tests/api_resources/test_customers.py b/tests/api_resources/test_customers.py index 392cefaa..38419de3 100644 --- a/tests/api_resources/test_customers.py +++ b/tests/api_resources/test_customers.py @@ -24,7 +24,7 @@ class TestCustomers: @parametrize def test_method_create(self, client: Orb) -> None: customer = client.customers.create( - email="email", + email="dev@stainlessapi.com", name="x", ) assert_matches_type(Customer, customer, path=["response"]) @@ -32,26 +32,18 @@ def test_method_create(self, client: Orb) -> None: @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: customer = client.customers.create( - email="email", + email="dev@stainlessapi.com", name="x", accounting_sync_configuration={ "accounting_providers": [ { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, - additional_emails=["string", "string", "string"], + additional_emails=["string"], auto_collection=True, billing_address={ "city": "city", @@ -76,6 +68,11 @@ def test_method_create_with_all_params(self, client: Orb) -> None: "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", @@ -88,7 +85,7 @@ def test_method_create_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_create(self, client: Orb) -> None: response = client.customers.with_raw_response.create( - email="email", + email="dev@stainlessapi.com", name="x", ) @@ -100,7 +97,7 @@ def test_raw_response_create(self, client: Orb) -> None: @parametrize def test_streaming_response_create(self, client: Orb) -> None: with client.customers.with_streaming_response.create( - email="email", + email="dev@stainlessapi.com", name="x", ) as response: assert not response.is_closed @@ -127,15 +124,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, @@ -150,7 +139,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: "state": "state", }, currency="currency", - email="email", + email="dev@stainlessapi.com", email_delivery=True, external_customer_id="external_customer_id", metadata={"foo": "string"}, @@ -166,6 +155,11 @@ def test_method_update_with_all_params(self, client: Orb) -> None: "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", @@ -372,15 +366,7 @@ def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, @@ -395,7 +381,7 @@ def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None "state": "state", }, currency="currency", - email="email", + email="dev@stainlessapi.com", email_delivery=True, external_customer_id="external_customer_id", metadata={"foo": "string"}, @@ -411,6 +397,11 @@ def test_method_update_by_external_id_with_all_params(self, client: Orb) -> None "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", @@ -458,7 +449,7 @@ class TestAsyncCustomers: @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.create( - email="email", + email="dev@stainlessapi.com", name="x", ) assert_matches_type(Customer, customer, path=["response"]) @@ -466,26 +457,18 @@ async def test_method_create(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: customer = await async_client.customers.create( - email="email", + email="dev@stainlessapi.com", name="x", accounting_sync_configuration={ "accounting_providers": [ { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, - additional_emails=["string", "string", "string"], + additional_emails=["string"], auto_collection=True, billing_address={ "city": "city", @@ -510,6 +493,11 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", @@ -522,7 +510,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: response = await async_client.customers.with_raw_response.create( - email="email", + email="dev@stainlessapi.com", name="x", ) @@ -534,7 +522,7 @@ async def test_raw_response_create(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: async with async_client.customers.with_streaming_response.create( - email="email", + email="dev@stainlessapi.com", name="x", ) as response: assert not response.is_closed @@ -561,15 +549,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, @@ -584,7 +564,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No "state": "state", }, currency="currency", - email="email", + email="dev@stainlessapi.com", email_delivery=True, external_customer_id="external_customer_id", metadata={"foo": "string"}, @@ -600,6 +580,11 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", @@ -806,15 +791,7 @@ async def test_method_update_by_external_id_with_all_params(self, async_client: { "external_provider_id": "external_provider_id", "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, - { - "external_provider_id": "external_provider_id", - "provider_type": "provider_type", - }, + } ], "excluded": True, }, @@ -829,7 +806,7 @@ async def test_method_update_by_external_id_with_all_params(self, async_client: "state": "state", }, currency="currency", - email="email", + email="dev@stainlessapi.com", email_delivery=True, external_customer_id="external_customer_id", metadata={"foo": "string"}, @@ -845,6 +822,11 @@ async def test_method_update_by_external_id_with_all_params(self, async_client: "postal_code": "postal_code", "state": "state", }, + tax_configuration={ + "tax_exempt": True, + "tax_provider": "avalara", + "tax_exemption_code": "tax_exemption_code", + }, tax_id={ "country": "AD", "type": "ad_nrt", diff --git a/tests/api_resources/test_events.py b/tests/api_resources/test_events.py index 7e77f4b4..0095a335 100644 --- a/tests/api_resources/test_events.py +++ b/tests/api_resources/test_events.py @@ -132,19 +132,7 @@ def test_method_ingest(self, client: Orb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -160,23 +148,7 @@ def test_method_ingest_with_all_params(self, client: Orb) -> None: "timestamp": parse_datetime("2020-12-09T16:09:53Z"), "customer_id": "customer_id", "external_customer_id": "external_customer_id", - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "customer_id": "customer_id", - "external_customer_id": "external_customer_id", - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "customer_id": "customer_id", - "external_customer_id": "external_customer_id", - }, + } ], backfill_id="backfill_id", debug=True, @@ -192,19 +164,7 @@ def test_raw_response_ingest(self, client: Orb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) @@ -222,19 +182,7 @@ def test_streaming_response_ingest(self, client: Orb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) as response: assert not response.is_closed @@ -398,19 +346,7 @@ async def test_method_ingest(self, async_client: AsyncOrb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) assert_matches_type(EventIngestResponse, event, path=["response"]) @@ -426,23 +362,7 @@ async def test_method_ingest_with_all_params(self, async_client: AsyncOrb) -> No "timestamp": parse_datetime("2020-12-09T16:09:53Z"), "customer_id": "customer_id", "external_customer_id": "external_customer_id", - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "customer_id": "customer_id", - "external_customer_id": "external_customer_id", - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - "customer_id": "customer_id", - "external_customer_id": "external_customer_id", - }, + } ], backfill_id="backfill_id", debug=True, @@ -458,19 +378,7 @@ async def test_raw_response_ingest(self, async_client: AsyncOrb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) @@ -488,19 +396,7 @@ async def test_streaming_response_ingest(self, async_client: AsyncOrb) -> None: "idempotency_key": "idempotency_key", "properties": {}, "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, - { - "event_name": "event_name", - "idempotency_key": "idempotency_key", - "properties": {}, - "timestamp": parse_datetime("2020-12-09T16:09:53Z"), - }, + } ], ) as response: assert not response.is_closed diff --git a/tests/api_resources/test_invoices.py b/tests/api_resources/test_invoices.py index 7121b809..4d379d1f 100644 --- a/tests/api_resources/test_invoices.py +++ b/tests/api_resources/test_invoices.py @@ -194,7 +194,7 @@ def test_method_list_with_all_params(self, client: Orb) -> None: invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), is_recurring=True, limit=1, - status=["draft", "issued", "paid"], + status=["draft"], subscription_id="subscription_id", ) assert_matches_type(SyncPage[Invoice], invoice, path=["response"]) @@ -259,11 +259,6 @@ def test_path_params_fetch(self, client: Orb) -> None: @parametrize def test_method_fetch_upcoming(self, client: Orb) -> None: - invoice = client.invoices.fetch_upcoming() - assert_matches_type(InvoiceFetchUpcomingResponse, invoice, path=["response"]) - - @parametrize - def test_method_fetch_upcoming_with_all_params(self, client: Orb) -> None: invoice = client.invoices.fetch_upcoming( subscription_id="subscription_id", ) @@ -271,7 +266,9 @@ def test_method_fetch_upcoming_with_all_params(self, client: Orb) -> None: @parametrize def test_raw_response_fetch_upcoming(self, client: Orb) -> None: - response = client.invoices.with_raw_response.fetch_upcoming() + response = client.invoices.with_raw_response.fetch_upcoming( + subscription_id="subscription_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -280,7 +277,9 @@ def test_raw_response_fetch_upcoming(self, client: Orb) -> None: @parametrize def test_streaming_response_fetch_upcoming(self, client: Orb) -> None: - with client.invoices.with_streaming_response.fetch_upcoming() as response: + with client.invoices.with_streaming_response.fetch_upcoming( + subscription_id="subscription_id", + ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -292,14 +291,22 @@ def test_streaming_response_fetch_upcoming(self, client: Orb) -> None: @parametrize def test_method_issue(self, client: Orb) -> None: invoice = client.invoices.issue( - "invoice_id", + invoice_id="invoice_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + def test_method_issue_with_all_params(self, client: Orb) -> None: + invoice = client.invoices.issue( + invoice_id="invoice_id", + synchronous=True, ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize def test_raw_response_issue(self, client: Orb) -> None: response = client.invoices.with_raw_response.issue( - "invoice_id", + invoice_id="invoice_id", ) assert response.is_closed is True @@ -310,7 +317,7 @@ def test_raw_response_issue(self, client: Orb) -> None: @parametrize def test_streaming_response_issue(self, client: Orb) -> None: with client.invoices.with_streaming_response.issue( - "invoice_id", + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -324,7 +331,7 @@ def test_streaming_response_issue(self, client: Orb) -> None: def test_path_params_issue(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): client.invoices.with_raw_response.issue( - "", + invoice_id="", ) @parametrize @@ -631,7 +638,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None invoice_date_lte=parse_datetime("2019-12-27T18:11:19.117Z"), is_recurring=True, limit=1, - status=["draft", "issued", "paid"], + status=["draft"], subscription_id="subscription_id", ) assert_matches_type(AsyncPage[Invoice], invoice, path=["response"]) @@ -696,11 +703,6 @@ async def test_path_params_fetch(self, async_client: AsyncOrb) -> None: @parametrize async def test_method_fetch_upcoming(self, async_client: AsyncOrb) -> None: - invoice = await async_client.invoices.fetch_upcoming() - assert_matches_type(InvoiceFetchUpcomingResponse, invoice, path=["response"]) - - @parametrize - async def test_method_fetch_upcoming_with_all_params(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.fetch_upcoming( subscription_id="subscription_id", ) @@ -708,7 +710,9 @@ async def test_method_fetch_upcoming_with_all_params(self, async_client: AsyncOr @parametrize async def test_raw_response_fetch_upcoming(self, async_client: AsyncOrb) -> None: - response = await async_client.invoices.with_raw_response.fetch_upcoming() + response = await async_client.invoices.with_raw_response.fetch_upcoming( + subscription_id="subscription_id", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -717,7 +721,9 @@ async def test_raw_response_fetch_upcoming(self, async_client: AsyncOrb) -> None @parametrize async def test_streaming_response_fetch_upcoming(self, async_client: AsyncOrb) -> None: - async with async_client.invoices.with_streaming_response.fetch_upcoming() as response: + async with async_client.invoices.with_streaming_response.fetch_upcoming( + subscription_id="subscription_id", + ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -729,14 +735,22 @@ async def test_streaming_response_fetch_upcoming(self, async_client: AsyncOrb) - @parametrize async def test_method_issue(self, async_client: AsyncOrb) -> None: invoice = await async_client.invoices.issue( - "invoice_id", + invoice_id="invoice_id", + ) + assert_matches_type(Invoice, invoice, path=["response"]) + + @parametrize + async def test_method_issue_with_all_params(self, async_client: AsyncOrb) -> None: + invoice = await async_client.invoices.issue( + invoice_id="invoice_id", + synchronous=True, ) assert_matches_type(Invoice, invoice, path=["response"]) @parametrize async def test_raw_response_issue(self, async_client: AsyncOrb) -> None: response = await async_client.invoices.with_raw_response.issue( - "invoice_id", + invoice_id="invoice_id", ) assert response.is_closed is True @@ -747,7 +761,7 @@ async def test_raw_response_issue(self, async_client: AsyncOrb) -> None: @parametrize async def test_streaming_response_issue(self, async_client: AsyncOrb) -> None: async with async_client.invoices.with_streaming_response.issue( - "invoice_id", + invoice_id="invoice_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -761,7 +775,7 @@ async def test_streaming_response_issue(self, async_client: AsyncOrb) -> None: async def test_path_params_issue(self, async_client: AsyncOrb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): await async_client.invoices.with_raw_response.issue( - "", + invoice_id="", ) @parametrize diff --git a/tests/api_resources/test_items.py b/tests/api_resources/test_items.py index fedf3cc2..c65f50ad 100644 --- a/tests/api_resources/test_items.py +++ b/tests/api_resources/test_items.py @@ -64,15 +64,7 @@ def test_method_update_with_all_params(self, client: Orb) -> None: { "external_connection_name": "stripe", "external_entity_id": "external_entity_id", - }, - { - "external_connection_name": "stripe", - "external_entity_id": "external_entity_id", - }, - { - "external_connection_name": "stripe", - "external_entity_id": "external_entity_id", - }, + } ], name="name", ) @@ -230,15 +222,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOrb) -> No { "external_connection_name": "stripe", "external_entity_id": "external_entity_id", - }, - { - "external_connection_name": "stripe", - "external_entity_id": "external_entity_id", - }, - { - "external_connection_name": "stripe", - "external_entity_id": "external_entity_id", - }, + } ], name="name", ) diff --git a/tests/api_resources/test_prices.py b/tests/api_resources/test_prices.py index a458a3be..12f7757b 100644 --- a/tests/api_resources/test_prices.py +++ b/tests/api_resources/test_prices.py @@ -188,20 +188,12 @@ def test_method_create_overload_3(self, client: Orb) -> None: item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -217,20 +209,12 @@ def test_method_create_with_all_params_overload_3(self, client: Orb) -> None: item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -261,20 +245,12 @@ def test_raw_response_create_overload_3(self, client: Orb) -> None: item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -294,20 +270,12 @@ def test_streaming_response_create_overload_3(self, client: Orb) -> None: item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -330,20 +298,12 @@ def test_method_create_overload_4(self, client: Orb) -> None: matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -360,20 +320,12 @@ def test_method_create_with_all_params_overload_4(self, client: Orb) -> None: matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -405,20 +357,12 @@ def test_raw_response_create_overload_4(self, client: Orb) -> None: matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -439,20 +383,12 @@ def test_streaming_response_create_overload_4(self, client: Orb) -> None: matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -479,15 +415,7 @@ def test_method_create_overload_5(self, client: Orb) -> None: { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) @@ -507,17 +435,7 @@ def test_method_create_with_all_params_overload_5(self, client: Orb) -> None: "first_unit": 0, "unit_amount": "unit_amount", "last_unit": 0, - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - "last_unit": 0, - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - "last_unit": 0, - }, + } ] }, billable_metric_id="billable_metric_id", @@ -551,15 +469,7 @@ def test_raw_response_create_overload_5(self, client: Orb) -> None: { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) @@ -582,15 +492,7 @@ def test_streaming_response_create_overload_5(self, client: Orb) -> None: { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) as response: @@ -615,15 +517,7 @@ def test_method_create_overload_6(self, client: Orb) -> None: { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) @@ -644,19 +538,7 @@ def test_method_create_with_all_params_overload_6(self, client: Orb) -> None: "minimum_amount": "minimum_amount", "maximum_amount": "maximum_amount", "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, + } ] }, billable_metric_id="billable_metric_id", @@ -690,15 +572,7 @@ def test_raw_response_create_overload_6(self, client: Orb) -> None: { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) @@ -721,15 +595,7 @@ def test_streaming_response_create_overload_6(self, client: Orb) -> None: { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) as response: @@ -820,7 +686,7 @@ def test_streaming_response_create_overload_7(self, client: Orb) -> None: @parametrize def test_method_create_overload_8(self, client: Orb) -> None: price = client.prices.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -838,17 +704,7 @@ def test_method_create_with_all_params_overload_8(self, client: Orb) -> None: "bps": 0, "maximum_amount": "maximum_amount", "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, + } ] }, cadence="annual", @@ -877,7 +733,7 @@ def test_method_create_with_all_params_overload_8(self, client: Orb) -> None: @parametrize def test_raw_response_create_overload_8(self, client: Orb) -> None: response = client.prices.with_raw_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -893,7 +749,7 @@ def test_raw_response_create_overload_8(self, client: Orb) -> None: @parametrize def test_streaming_response_create_overload_8(self, client: Orb) -> None: with client.prices.with_streaming_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -911,13 +767,7 @@ def test_streaming_response_create_overload_8(self, client: Orb) -> None: @parametrize def test_method_create_overload_9(self, client: Orb) -> None: price = client.prices.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -934,15 +784,7 @@ def test_method_create_with_all_params_overload_9(self, client: Orb) -> None: { "unit_amount": "unit_amount", "maximum_units": 0, - }, - { - "unit_amount": "unit_amount", - "maximum_units": 0, - }, - { - "unit_amount": "unit_amount", - "maximum_units": 0, - }, + } ] }, cadence="annual", @@ -971,13 +813,7 @@ def test_method_create_with_all_params_overload_9(self, client: Orb) -> None: @parametrize def test_raw_response_create_overload_9(self, client: Orb) -> None: response = client.prices.with_raw_response.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -993,13 +829,7 @@ def test_raw_response_create_overload_9(self, client: Orb) -> None: @parametrize def test_streaming_response_create_overload_9(self, client: Orb) -> None: with client.prices.with_streaming_response.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -1819,6 +1649,152 @@ def test_streaming_response_create_overload_20(self, client: Orb) -> None: @parametrize def test_method_create_overload_21(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_21(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_21(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_21(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_22(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_method_create_with_all_params_overload_22(self, client: Orb) -> None: + price = client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_raw_response_create_overload_22(self, client: Orb) -> None: + response = client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + def test_streaming_response_create_overload_22(self, client: Orb) -> None: + with client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_overload_23(self, client: Orb) -> None: price = client.prices.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -1830,7 +1806,7 @@ def test_method_create_overload_21(self, client: Orb) -> None: assert_matches_type(Price, price, path=["response"]) @parametrize - def test_method_create_with_all_params_overload_21(self, client: Orb) -> None: + def test_method_create_with_all_params_overload_23(self, client: Orb) -> None: price = client.prices.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -1857,7 +1833,7 @@ def test_method_create_with_all_params_overload_21(self, client: Orb) -> None: assert_matches_type(Price, price, path=["response"]) @parametrize - def test_raw_response_create_overload_21(self, client: Orb) -> None: + def test_raw_response_create_overload_23(self, client: Orb) -> None: response = client.prices.with_raw_response.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -1873,7 +1849,7 @@ def test_raw_response_create_overload_21(self, client: Orb) -> None: assert_matches_type(Price, price, path=["response"]) @parametrize - def test_streaming_response_create_overload_21(self, client: Orb) -> None: + def test_streaming_response_create_overload_23(self, client: Orb) -> None: with client.prices.with_streaming_response.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -2309,20 +2285,12 @@ async def test_method_create_overload_3(self, async_client: AsyncOrb) -> None: item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -2338,20 +2306,12 @@ async def test_method_create_with_all_params_overload_3(self, async_client: Asyn item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -2382,20 +2342,12 @@ async def test_raw_response_create_overload_3(self, async_client: AsyncOrb) -> N item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -2415,20 +2367,12 @@ async def test_streaming_response_create_overload_3(self, async_client: AsyncOrb item_id="item_id", matrix_config={ "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix", @@ -2451,20 +2395,12 @@ async def test_method_create_overload_4(self, async_client: AsyncOrb) -> None: matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -2481,20 +2417,12 @@ async def test_method_create_with_all_params_overload_4(self, async_client: Asyn matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -2526,20 +2454,12 @@ async def test_raw_response_create_overload_4(self, async_client: AsyncOrb) -> N matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -2560,20 +2480,12 @@ async def test_streaming_response_create_overload_4(self, async_client: AsyncOrb matrix_with_allocation_config={ "allocation": 0, "default_unit_amount": "default_unit_amount", - "dimensions": ["string", "string", "string"], + "dimensions": ["string"], "matrix_values": [ { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], + "dimension_values": ["string"], "unit_amount": "unit_amount", - }, - { - "dimension_values": ["string", "string", "string"], - "unit_amount": "unit_amount", - }, + } ], }, model_type="matrix_with_allocation", @@ -2600,15 +2512,7 @@ async def test_method_create_overload_5(self, async_client: AsyncOrb) -> None: { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) @@ -2628,17 +2532,7 @@ async def test_method_create_with_all_params_overload_5(self, async_client: Asyn "first_unit": 0, "unit_amount": "unit_amount", "last_unit": 0, - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - "last_unit": 0, - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - "last_unit": 0, - }, + } ] }, billable_metric_id="billable_metric_id", @@ -2672,15 +2566,7 @@ async def test_raw_response_create_overload_5(self, async_client: AsyncOrb) -> N { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) @@ -2703,15 +2589,7 @@ async def test_streaming_response_create_overload_5(self, async_client: AsyncOrb { "first_unit": 0, "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, - { - "first_unit": 0, - "unit_amount": "unit_amount", - }, + } ] }, ) as response: @@ -2736,15 +2614,7 @@ async def test_method_create_overload_6(self, async_client: AsyncOrb) -> None: { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) @@ -2765,19 +2635,7 @@ async def test_method_create_with_all_params_overload_6(self, async_client: Asyn "minimum_amount": "minimum_amount", "maximum_amount": "maximum_amount", "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, + } ] }, billable_metric_id="billable_metric_id", @@ -2811,15 +2669,7 @@ async def test_raw_response_create_overload_6(self, async_client: AsyncOrb) -> N { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) @@ -2842,15 +2692,7 @@ async def test_streaming_response_create_overload_6(self, async_client: AsyncOrb { "bps": 0, "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, - { - "bps": 0, - "minimum_amount": "minimum_amount", - }, + } ] }, ) as response: @@ -2941,7 +2783,7 @@ async def test_streaming_response_create_overload_7(self, async_client: AsyncOrb @parametrize async def test_method_create_overload_8(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -2959,17 +2801,7 @@ async def test_method_create_with_all_params_overload_8(self, async_client: Asyn "bps": 0, "maximum_amount": "maximum_amount", "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, - { - "bps": 0, - "maximum_amount": "maximum_amount", - "per_unit_maximum": "per_unit_maximum", - }, + } ] }, cadence="annual", @@ -2998,7 +2830,7 @@ async def test_method_create_with_all_params_overload_8(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_8(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -3014,7 +2846,7 @@ async def test_raw_response_create_overload_8(self, async_client: AsyncOrb) -> N @parametrize async def test_streaming_response_create_overload_8(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( - bulk_bps_config={"tiers": [{"bps": 0}, {"bps": 0}, {"bps": 0}]}, + bulk_bps_config={"tiers": [{"bps": 0}]}, cadence="annual", currency="currency", item_id="item_id", @@ -3032,13 +2864,7 @@ async def test_streaming_response_create_overload_8(self, async_client: AsyncOrb @parametrize async def test_method_create_overload_9(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -3055,15 +2881,7 @@ async def test_method_create_with_all_params_overload_9(self, async_client: Asyn { "unit_amount": "unit_amount", "maximum_units": 0, - }, - { - "unit_amount": "unit_amount", - "maximum_units": 0, - }, - { - "unit_amount": "unit_amount", - "maximum_units": 0, - }, + } ] }, cadence="annual", @@ -3092,13 +2910,7 @@ async def test_method_create_with_all_params_overload_9(self, async_client: Asyn @parametrize async def test_raw_response_create_overload_9(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -3114,13 +2926,7 @@ async def test_raw_response_create_overload_9(self, async_client: AsyncOrb) -> N @parametrize async def test_streaming_response_create_overload_9(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( - bulk_config={ - "tiers": [ - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - {"unit_amount": "unit_amount"}, - ] - }, + bulk_config={"tiers": [{"unit_amount": "unit_amount"}]}, cadence="annual", currency="currency", item_id="item_id", @@ -3940,6 +3746,152 @@ async def test_streaming_response_create_overload_20(self, async_client: AsyncOr @parametrize async def test_method_create_overload_21(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_21(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_21(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_21(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + grouped_with_metered_minimum_config={"foo": "bar"}, + item_id="item_id", + model_type="grouped_with_metered_minimum", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = await response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_22(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_method_create_with_all_params_overload_22(self, async_client: AsyncOrb) -> None: + price = await async_client.prices.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + billable_metric_id="billable_metric_id", + billed_in_advance=True, + billing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + conversion_rate=0, + external_price_id="external_price_id", + fixed_price_quantity=0, + invoice_grouping_key="invoice_grouping_key", + invoicing_cycle_configuration={ + "duration": 0, + "duration_unit": "day", + }, + metadata={"foo": "string"}, + ) + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_raw_response_create_overload_22(self, async_client: AsyncOrb) -> None: + response = await async_client.prices.with_raw_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + price = response.parse() + assert_matches_type(Price, price, path=["response"]) + + @parametrize + async def test_streaming_response_create_overload_22(self, async_client: AsyncOrb) -> None: + async with async_client.prices.with_streaming_response.create( + cadence="annual", + currency="currency", + item_id="item_id", + matrix_with_display_name_config={"foo": "bar"}, + model_type="matrix_with_display_name", + name="Annual fee", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + price = await response.parse() + assert_matches_type(Price, price, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_overload_23(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -3951,7 +3903,7 @@ async def test_method_create_overload_21(self, async_client: AsyncOrb) -> None: assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_method_create_with_all_params_overload_21(self, async_client: AsyncOrb) -> None: + async def test_method_create_with_all_params_overload_23(self, async_client: AsyncOrb) -> None: price = await async_client.prices.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -3978,7 +3930,7 @@ async def test_method_create_with_all_params_overload_21(self, async_client: Asy assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_raw_response_create_overload_21(self, async_client: AsyncOrb) -> None: + async def test_raw_response_create_overload_23(self, async_client: AsyncOrb) -> None: response = await async_client.prices.with_raw_response.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", @@ -3994,7 +3946,7 @@ async def test_raw_response_create_overload_21(self, async_client: AsyncOrb) -> assert_matches_type(Price, price, path=["response"]) @parametrize - async def test_streaming_response_create_overload_21(self, async_client: AsyncOrb) -> None: + async def test_streaming_response_create_overload_23(self, async_client: AsyncOrb) -> None: async with async_client.prices.with_streaming_response.create( bulk_with_proration_config={"foo": "bar"}, cadence="annual", diff --git a/tests/api_resources/test_subscriptions.py b/tests/api_resources/test_subscriptions.py index 61fcc04f..6caa8672 100644 --- a/tests/api_resources/test_subscriptions.py +++ b/tests/api_resources/test_subscriptions.py @@ -11,8 +11,18 @@ from orb.types import ( Subscription, SubscriptionUsage, + SubscriptionCancelResponse, + SubscriptionCreateResponse, SubscriptionFetchCostsResponse, + SubscriptionUpdateTrialResponse, + SubscriptionTriggerPhaseResponse, SubscriptionFetchScheduleResponse, + SubscriptionPriceIntervalsResponse, + SubscriptionSchedulePlanChangeResponse, + SubscriptionUnscheduleCancellationResponse, + SubscriptionUpdateFixedFeeQuantityResponse, + SubscriptionUnschedulePendingPlanChangesResponse, + SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, ) from orb._utils import parse_date, parse_datetime from tests.utils import assert_matches_type @@ -27,11 +37,67 @@ class TestSubscriptions: @parametrize def test_method_create(self, client: Orb) -> None: subscription = client.subscriptions.create() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Orb) -> None: subscription = client.subscriptions.create( + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, + }, + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "plan_phase_order": 0, + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + add_prices=[ + { + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "external_price_id": "external_price_id", + "maximum_amount": "1.23", + "minimum_amount": "1.23", + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], align_billing_with_subscription_start_date=True, auto_collection=True, aws_region="aws_region", @@ -49,71 +115,79 @@ def test_method_create_with_all_params(self, client: Orb) -> None: external_marketplace="google", external_marketplace_reporting_id="external_marketplace_reporting_id", external_plan_id="ZMwNQefe7J3ecf7W", + filter="my_property > 100 AND my_other_property = 'bar'", initial_phase_order=2, invoicing_threshold="10.00", metadata={"foo": "string"}, net_terms=0, per_credit_overage_amount=0, plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, + "replaces_price_id": "replaces_price_id", + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "external_price_id": "external_price_id", "fixed_price_quantity": 2, "maximum_amount": "1.23", "minimum_amount": "1.23", - }, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + } ], start_date=parse_datetime("2019-12-27T18:11:19.117Z"), + trial_duration_days=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize def test_raw_response_create(self, client: Orb) -> None: @@ -122,7 +196,7 @@ def test_raw_response_create(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize def test_streaming_response_create(self, client: Orb) -> None: @@ -131,7 +205,7 @@ def test_streaming_response_create(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -198,7 +272,7 @@ def test_method_list_with_all_params(self, client: Orb) -> None: created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), cursor="cursor", - customer_id=["string", "string", "string"], + customer_id=["string"], external_customer_id="external_customer_id", limit=1, status="active", @@ -231,7 +305,7 @@ def test_method_cancel(self, client: Orb) -> None: subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize def test_method_cancel_with_all_params(self, client: Orb) -> None: @@ -240,7 +314,7 @@ def test_method_cancel_with_all_params(self, client: Orb) -> None: cancel_option="end_of_subscription_term", cancellation_date=parse_datetime("2019-12-27T18:11:19.117Z"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize def test_raw_response_cancel(self, client: Orb) -> None: @@ -252,7 +326,7 @@ def test_raw_response_cancel(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize def test_streaming_response_cancel(self, client: Orb) -> None: @@ -264,7 +338,7 @@ def test_streaming_response_cancel(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -480,7 +554,7 @@ def test_method_price_intervals(self, client: Orb) -> None: subscription = client.subscriptions.price_intervals( subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize @@ -500,15 +574,7 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: { "amount_discount": 0, "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, + } ], "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), "external_price_id": "external_price_id", @@ -516,15 +582,7 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: { "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + } ], "maximum_amount": 0, "minimum_amount": 0, @@ -552,50 +610,121 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: "metadata": {"foo": "string"}, }, "price_id": "h74gfhdjvn7ujokd", - }, + } + ], + add_adjustments=[ { - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "allocation_price": { - "amount": "10.00", - "cadence": "one_time", - "currency": "USD", - "expires_at_end_of_cadence": True, + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, }, - "discounts": [ - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - ], + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + edit=[ + { + "price_interval_id": "sdfs6wdjvn7ujokd", + "billing_cycle_day": 0, "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "external_price_id": "external_price_id", "fixed_fee_quantity_transitions": [ { "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + } + ], + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + edit_adjustments=[ + { + "adjustment_interval_id": "sdfs6wdjvn7ujokd", + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + ) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) + + @pytest.mark.skip(reason="Incorrect example breaks Prism") + @parametrize + def test_raw_response_price_intervals(self, client: Orb) -> None: + response = client.subscriptions.with_raw_response.price_intervals( + subscription_id="subscription_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) + + @pytest.mark.skip(reason="Incorrect example breaks Prism") + @parametrize + def test_streaming_response_price_intervals(self, client: Orb) -> None: + with client.subscriptions.with_streaming_response.price_intervals( + subscription_id="subscription_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = response.parse() + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Incorrect example breaks Prism") + @parametrize + def test_path_params_price_intervals(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): + client.subscriptions.with_raw_response.price_intervals( + subscription_id="", + ) + + @parametrize + def test_method_schedule_plan_change(self, client: Orb) -> None: + subscription = client.subscriptions.schedule_plan_change( + subscription_id="subscription_id", + change_option="requested_date", + ) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) + + @parametrize + def test_method_schedule_plan_change_with_all_params(self, client: Orb) -> None: + subscription = client.subscriptions.schedule_plan_change( + subscription_id="subscription_id", + change_option="requested_date", + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, + }, + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "plan_phase_order": 0, + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + add_prices=[ + { + "discounts": [ { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } ], - "maximum_amount": 0, - "minimum_amount": 0, + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "external_price_id": "external_price_id", + "maximum_amount": "1.23", + "minimum_amount": "1.23", + "plan_phase_order": 0, "price": { "cadence": "annual", - "currency": "currency", "item_id": "item_id", "model_type": "unit", "name": "Annual fee", @@ -607,6 +736,7 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: "duration_unit": "day", }, "conversion_rate": 0, + "currency": "currency", "external_price_id": "external_price_id", "fixed_price_quantity": 0, "invoice_grouping_key": "invoice_grouping_key", @@ -615,52 +745,68 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: "duration_unit": "day", }, "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, "price_id": "h74gfhdjvn7ujokd", - }, - { "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "allocation_price": { - "amount": "10.00", - "cadence": "one_time", - "currency": "USD", - "expires_at_end_of_cadence": True, - }, - "discounts": [ - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - ], - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "external_price_id": "external_price_id", - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + } + ], + align_billing_with_plan_change_date=True, + auto_collection=True, + billing_cycle_alignment="unchanged", + billing_cycle_anchor_configuration={ + "day": 1, + "month": 1, + "year": 0, + }, + change_date=parse_datetime("2017-07-21T17:32:28Z"), + coupon_redemption_code="coupon_redemption_code", + credits_overage_rate=0, + default_invoice_memo="default_invoice_memo", + external_plan_id="ZMwNQefe7J3ecf7W", + filter="my_property > 100 AND my_other_property = 'bar'", + initial_phase_order=2, + invoicing_threshold="10.00", + net_terms=0, + per_credit_overage_amount=0, + plan_id="ZMwNQefe7J3ecf7W", + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ + { + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, + }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ + { + "replaces_price_id": "replaces_price_id", + "discounts": [ { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } ], - "maximum_amount": 0, - "minimum_amount": 0, + "external_price_id": "external_price_id", + "fixed_price_quantity": 2, + "maximum_amount": "1.23", + "minimum_amount": "1.23", "price": { "cadence": "annual", - "currency": "currency", "item_id": "item_id", "model_type": "unit", "name": "Annual fee", @@ -672,6 +818,7 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: "duration_unit": "day", }, "conversion_rate": 0, + "currency": "currency", "external_price_id": "external_price_id", "fixed_price_quantity": 0, "invoice_grouping_key": "invoice_grouping_key", @@ -680,239 +827,14 @@ def test_method_price_intervals_with_all_params(self, client: Orb) -> None: "duration_unit": "day", }, "metadata": {"foo": "string"}, + "reference_id": "reference_id", }, "price_id": "h74gfhdjvn7ujokd", - }, - ], - add_adjustments=[ - { - "adjustment": { - "adjustment_type": "percentage_discount", - "applies_to_price_ids": ["price_1", "price_2"], - "percentage_discount": 0, - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment": { - "adjustment_type": "percentage_discount", - "applies_to_price_ids": ["price_1", "price_2"], - "percentage_discount": 0, - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment": { - "adjustment_type": "percentage_discount", - "applies_to_price_ids": ["price_1", "price_2"], - "percentage_discount": 0, - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - edit=[ - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "billing_cycle_day": 0, - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "billing_cycle_day": 0, - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "billing_cycle_day": 0, - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - edit_adjustments=[ - { - "adjustment_interval_id": "sdfs6wdjvn7ujokd", - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment_interval_id": "sdfs6wdjvn7ujokd", - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment_interval_id": "sdfs6wdjvn7ujokd", - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ], - ) - assert_matches_type(Subscription, subscription, path=["response"]) - - @pytest.mark.skip(reason="Incorrect example breaks Prism") - @parametrize - def test_raw_response_price_intervals(self, client: Orb) -> None: - response = client.subscriptions.with_raw_response.price_intervals( - subscription_id="subscription_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) - - @pytest.mark.skip(reason="Incorrect example breaks Prism") - @parametrize - def test_streaming_response_price_intervals(self, client: Orb) -> None: - with client.subscriptions.with_streaming_response.price_intervals( - subscription_id="subscription_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Incorrect example breaks Prism") - @parametrize - def test_path_params_price_intervals(self, client: Orb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): - client.subscriptions.with_raw_response.price_intervals( - subscription_id="", - ) - - @parametrize - def test_method_schedule_plan_change(self, client: Orb) -> None: - subscription = client.subscriptions.schedule_plan_change( - subscription_id="subscription_id", - change_option="requested_date", - ) - assert_matches_type(Subscription, subscription, path=["response"]) - - @parametrize - def test_method_schedule_plan_change_with_all_params(self, client: Orb) -> None: - subscription = client.subscriptions.schedule_plan_change( - subscription_id="subscription_id", - change_option="requested_date", - align_billing_with_plan_change_date=True, - auto_collection=True, - billing_cycle_alignment="unchanged", - change_date=parse_datetime("2017-07-21T17:32:28Z"), - coupon_redemption_code="coupon_redemption_code", - credits_overage_rate=0, - default_invoice_memo="default_invoice_memo", - external_plan_id="ZMwNQefe7J3ecf7W", - initial_phase_order=2, - invoicing_threshold="10.00", - net_terms=0, - per_credit_overage_amount=0, - plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ - { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, - { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, - { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + } ], + trial_duration_days=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) @parametrize def test_raw_response_schedule_plan_change(self, client: Orb) -> None: @@ -924,7 +846,7 @@ def test_raw_response_schedule_plan_change(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) @parametrize def test_streaming_response_schedule_plan_change(self, client: Orb) -> None: @@ -936,7 +858,7 @@ def test_streaming_response_schedule_plan_change(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -953,7 +875,7 @@ def test_method_trigger_phase(self, client: Orb) -> None: subscription = client.subscriptions.trigger_phase( subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize def test_method_trigger_phase_with_all_params(self, client: Orb) -> None: @@ -961,7 +883,7 @@ def test_method_trigger_phase_with_all_params(self, client: Orb) -> None: subscription_id="subscription_id", effective_date=parse_date("2019-12-27"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize def test_raw_response_trigger_phase(self, client: Orb) -> None: @@ -972,7 +894,7 @@ def test_raw_response_trigger_phase(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize def test_streaming_response_trigger_phase(self, client: Orb) -> None: @@ -983,7 +905,7 @@ def test_streaming_response_trigger_phase(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -999,7 +921,7 @@ def test_method_unschedule_cancellation(self, client: Orb) -> None: subscription = client.subscriptions.unschedule_cancellation( "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_cancellation(self, client: Orb) -> None: @@ -1010,7 +932,7 @@ def test_raw_response_unschedule_cancellation(self, client: Orb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_cancellation(self, client: Orb) -> None: @@ -1021,7 +943,7 @@ def test_streaming_response_unschedule_cancellation(self, client: Orb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1038,7 +960,7 @@ def test_method_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None subscription_id="subscription_id", price_id="price_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None: @@ -1050,7 +972,7 @@ def test_raw_response_unschedule_fixed_fee_quantity_updates(self, client: Orb) - assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, client: Orb) -> None: @@ -1062,7 +984,7 @@ def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, client: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1079,7 +1001,7 @@ def test_method_unschedule_pending_plan_changes(self, client: Orb) -> None: subscription = client.subscriptions.unschedule_pending_plan_changes( "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) @parametrize def test_raw_response_unschedule_pending_plan_changes(self, client: Orb) -> None: @@ -1090,7 +1012,7 @@ def test_raw_response_unschedule_pending_plan_changes(self, client: Orb) -> None assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) @parametrize def test_streaming_response_unschedule_pending_plan_changes(self, client: Orb) -> None: @@ -1101,7 +1023,7 @@ def test_streaming_response_unschedule_pending_plan_changes(self, client: Orb) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1119,7 +1041,7 @@ def test_method_update_fixed_fee_quantity(self, client: Orb) -> None: price_id="price_id", quantity=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) @parametrize def test_method_update_fixed_fee_quantity_with_all_params(self, client: Orb) -> None: @@ -1130,43 +1052,94 @@ def test_method_update_fixed_fee_quantity_with_all_params(self, client: Orb) -> change_option="immediate", effective_date=parse_date("2022-12-21"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) @parametrize def test_raw_response_update_fixed_fee_quantity(self, client: Orb) -> None: response = client.subscriptions.with_raw_response.update_fixed_fee_quantity( subscription_id="subscription_id", - price_id="price_id", - quantity=0, + price_id="price_id", + quantity=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) + + @parametrize + def test_streaming_response_update_fixed_fee_quantity(self, client: Orb) -> None: + with client.subscriptions.with_streaming_response.update_fixed_fee_quantity( + subscription_id="subscription_id", + price_id="price_id", + quantity=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = response.parse() + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update_fixed_fee_quantity(self, client: Orb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): + client.subscriptions.with_raw_response.update_fixed_fee_quantity( + subscription_id="", + price_id="price_id", + quantity=0, + ) + + @parametrize + def test_method_update_trial(self, client: Orb) -> None: + subscription = client.subscriptions.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + @parametrize + def test_method_update_trial_with_all_params(self, client: Orb) -> None: + subscription = client.subscriptions.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + shift=True, + ) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + @parametrize + def test_raw_response_update_trial(self, client: Orb) -> None: + response = client.subscriptions.with_raw_response.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) @parametrize - def test_streaming_response_update_fixed_fee_quantity(self, client: Orb) -> None: - with client.subscriptions.with_streaming_response.update_fixed_fee_quantity( + def test_streaming_response_update_trial(self, client: Orb) -> None: + with client.subscriptions.with_streaming_response.update_trial( subscription_id="subscription_id", - price_id="price_id", - quantity=0, + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_update_fixed_fee_quantity(self, client: Orb) -> None: + def test_path_params_update_trial(self, client: Orb) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): - client.subscriptions.with_raw_response.update_fixed_fee_quantity( + client.subscriptions.with_raw_response.update_trial( subscription_id="", - price_id="price_id", - quantity=0, + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), ) @@ -1176,11 +1149,67 @@ class TestAsyncSubscriptions: @parametrize async def test_method_create(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.create() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.create( + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, + }, + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "plan_phase_order": 0, + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + add_prices=[ + { + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "external_price_id": "external_price_id", + "maximum_amount": "1.23", + "minimum_amount": "1.23", + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], align_billing_with_subscription_start_date=True, auto_collection=True, aws_region="aws_region", @@ -1198,71 +1227,79 @@ async def test_method_create_with_all_params(self, async_client: AsyncOrb) -> No external_marketplace="google", external_marketplace_reporting_id="external_marketplace_reporting_id", external_plan_id="ZMwNQefe7J3ecf7W", + filter="my_property > 100 AND my_other_property = 'bar'", initial_phase_order=2, invoicing_threshold="10.00", metadata={"foo": "string"}, net_terms=0, per_credit_overage_amount=0, plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, + "replaces_price_id": "replaces_price_id", + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "external_price_id": "external_price_id", "fixed_price_quantity": 2, "maximum_amount": "1.23", "minimum_amount": "1.23", - }, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + } ], start_date=parse_datetime("2019-12-27T18:11:19.117Z"), + trial_duration_days=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncOrb) -> None: @@ -1271,7 +1308,7 @@ async def test_raw_response_create(self, async_client: AsyncOrb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: @@ -1280,7 +1317,7 @@ async def test_streaming_response_create(self, async_client: AsyncOrb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCreateResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1347,7 +1384,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOrb) -> None created_at_lt=parse_datetime("2019-12-27T18:11:19.117Z"), created_at_lte=parse_datetime("2019-12-27T18:11:19.117Z"), cursor="cursor", - customer_id=["string", "string", "string"], + customer_id=["string"], external_customer_id="external_customer_id", limit=1, status="active", @@ -1380,7 +1417,7 @@ async def test_method_cancel(self, async_client: AsyncOrb) -> None: subscription_id="subscription_id", cancel_option="end_of_subscription_term", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize async def test_method_cancel_with_all_params(self, async_client: AsyncOrb) -> None: @@ -1389,7 +1426,7 @@ async def test_method_cancel_with_all_params(self, async_client: AsyncOrb) -> No cancel_option="end_of_subscription_term", cancellation_date=parse_datetime("2019-12-27T18:11:19.117Z"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None: @@ -1401,7 +1438,7 @@ async def test_raw_response_cancel(self, async_client: AsyncOrb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: @@ -1413,7 +1450,7 @@ async def test_streaming_response_cancel(self, async_client: AsyncOrb) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionCancelResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1617,156 +1654,26 @@ async def test_streaming_response_fetch_usage(self, async_client: AsyncOrb) -> N @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize - async def test_path_params_fetch_usage(self, async_client: AsyncOrb) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): - await async_client.subscriptions.with_raw_response.fetch_usage( - subscription_id="", - ) - - @pytest.mark.skip(reason="Incorrect example breaks Prism") - @parametrize - async def test_method_price_intervals(self, async_client: AsyncOrb) -> None: - subscription = await async_client.subscriptions.price_intervals( - subscription_id="subscription_id", - ) - assert_matches_type(Subscription, subscription, path=["response"]) - - @pytest.mark.skip(reason="Incorrect example breaks Prism") - @parametrize - async def test_method_price_intervals_with_all_params(self, async_client: AsyncOrb) -> None: - subscription = await async_client.subscriptions.price_intervals( - subscription_id="subscription_id", - add=[ - { - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "allocation_price": { - "amount": "10.00", - "cadence": "one_time", - "currency": "USD", - "expires_at_end_of_cadence": True, - }, - "discounts": [ - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - ], - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "external_price_id": "external_price_id", - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "maximum_amount": 0, - "minimum_amount": 0, - "price": { - "cadence": "annual", - "currency": "currency", - "item_id": "item_id", - "model_type": "unit", - "name": "Annual fee", - "unit_config": {"unit_amount": "unit_amount"}, - "billable_metric_id": "billable_metric_id", - "billed_in_advance": True, - "billing_cycle_configuration": { - "duration": 0, - "duration_unit": "day", - }, - "conversion_rate": 0, - "external_price_id": "external_price_id", - "fixed_price_quantity": 0, - "invoice_grouping_key": "invoice_grouping_key", - "invoicing_cycle_configuration": { - "duration": 0, - "duration_unit": "day", - }, - "metadata": {"foo": "string"}, - }, - "price_id": "h74gfhdjvn7ujokd", - }, - { - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "allocation_price": { - "amount": "10.00", - "cadence": "one_time", - "currency": "USD", - "expires_at_end_of_cadence": True, - }, - "discounts": [ - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - ], - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "external_price_id": "external_price_id", - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "maximum_amount": 0, - "minimum_amount": 0, - "price": { - "cadence": "annual", - "currency": "currency", - "item_id": "item_id", - "model_type": "unit", - "name": "Annual fee", - "unit_config": {"unit_amount": "unit_amount"}, - "billable_metric_id": "billable_metric_id", - "billed_in_advance": True, - "billing_cycle_configuration": { - "duration": 0, - "duration_unit": "day", - }, - "conversion_rate": 0, - "external_price_id": "external_price_id", - "fixed_price_quantity": 0, - "invoice_grouping_key": "invoice_grouping_key", - "invoicing_cycle_configuration": { - "duration": 0, - "duration_unit": "day", - }, - "metadata": {"foo": "string"}, - }, - "price_id": "h74gfhdjvn7ujokd", - }, + async def test_path_params_fetch_usage(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): + await async_client.subscriptions.with_raw_response.fetch_usage( + subscription_id="", + ) + + @pytest.mark.skip(reason="Incorrect example breaks Prism") + @parametrize + async def test_method_price_intervals(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.price_intervals( + subscription_id="subscription_id", + ) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) + + @pytest.mark.skip(reason="Incorrect example breaks Prism") + @parametrize + async def test_method_price_intervals_with_all_params(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.price_intervals( + subscription_id="subscription_id", + add=[ { "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), "allocation_price": { @@ -1779,15 +1686,7 @@ async def test_method_price_intervals_with_all_params(self, async_client: AsyncO { "amount_discount": 0, "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, - { - "amount_discount": 0, - "discount_type": "amount", - }, + } ], "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), "external_price_id": "external_price_id", @@ -1795,15 +1694,7 @@ async def test_method_price_intervals_with_all_params(self, async_client: AsyncO { "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + } ], "maximum_amount": 0, "minimum_amount": 0, @@ -1831,7 +1722,7 @@ async def test_method_price_intervals_with_all_params(self, async_client: AsyncO "metadata": {"foo": "string"}, }, "price_id": "h74gfhdjvn7ujokd", - }, + } ], add_adjustments=[ { @@ -1839,28 +1730,11 @@ async def test_method_price_intervals_with_all_params(self, async_client: AsyncO "adjustment_type": "percentage_discount", "applies_to_price_ids": ["price_1", "price_2"], "percentage_discount": 0, + "is_invoice_level": True, }, "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment": { - "adjustment_type": "percentage_discount", - "applies_to_price_ids": ["price_1", "price_2"], - "percentage_discount": 0, - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment": { - "adjustment_type": "percentage_discount", - "applies_to_price_ids": ["price_1", "price_2"], - "percentage_discount": 0, - }, - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], edit=[ { @@ -1871,78 +1745,20 @@ async def test_method_price_intervals_with_all_params(self, async_client: AsyncO { "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "billing_cycle_day": 0, - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - ], - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "price_interval_id": "sdfs6wdjvn7ujokd", - "billing_cycle_day": 0, - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "fixed_fee_quantity_transitions": [ - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, - { - "effective_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 5, - }, + } ], "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], edit_adjustments=[ { "adjustment_interval_id": "sdfs6wdjvn7ujokd", "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment_interval_id": "sdfs6wdjvn7ujokd", - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "adjustment_interval_id": "sdfs6wdjvn7ujokd", - "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize @@ -1954,7 +1770,7 @@ async def test_raw_response_price_intervals(self, async_client: AsyncOrb) -> Non assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) @pytest.mark.skip(reason="Incorrect example breaks Prism") @parametrize @@ -1966,7 +1782,7 @@ async def test_streaming_response_price_intervals(self, async_client: AsyncOrb) assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionPriceIntervalsResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1984,84 +1800,153 @@ async def test_method_schedule_plan_change(self, async_client: AsyncOrb) -> None subscription_id="subscription_id", change_option="requested_date", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) @parametrize async def test_method_schedule_plan_change_with_all_params(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.schedule_plan_change( subscription_id="subscription_id", change_option="requested_date", + add_adjustments=[ + { + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, + }, + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "plan_phase_order": 0, + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], + add_prices=[ + { + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "end_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "external_price_id": "external_price_id", + "maximum_amount": "1.23", + "minimum_amount": "1.23", + "plan_phase_order": 0, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + "start_date": parse_datetime("2019-12-27T18:11:19.117Z"), + } + ], align_billing_with_plan_change_date=True, auto_collection=True, billing_cycle_alignment="unchanged", + billing_cycle_anchor_configuration={ + "day": 1, + "month": 1, + "year": 0, + }, change_date=parse_datetime("2017-07-21T17:32:28Z"), coupon_redemption_code="coupon_redemption_code", credits_overage_rate=0, default_invoice_memo="default_invoice_memo", external_plan_id="ZMwNQefe7J3ecf7W", + filter="my_property > 100 AND my_other_property = 'bar'", initial_phase_order=2, invoicing_threshold="10.00", net_terms=0, per_credit_overage_amount=0, plan_id="ZMwNQefe7J3ecf7W", - price_overrides=[ + plan_version_number=0, + price_overrides=[{}], + remove_adjustments=[{"adjustment_id": "h74gfhdjvn7ujokd"}], + remove_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "external_price_id": "external_price_id", + "price_id": "h74gfhdjvn7ujokd", + } + ], + replace_adjustments=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, + "adjustment": { + "adjustment_type": "percentage_discount", + "applies_to_price_ids": ["price_1", "price_2"], + "percentage_discount": 0, + "is_invoice_level": True, }, - "fixed_price_quantity": 2, - "maximum_amount": "1.23", - "minimum_amount": "1.23", - }, + "replaces_adjustment_id": "replaces_adjustment_id", + } + ], + replace_prices=[ { - "id": "id", - "model_type": "unit", - "unit_config": {"unit_amount": "unit_amount"}, - "conversion_rate": 0, - "currency": "currency", - "discount": { - "discount_type": "percentage", - "amount_discount": "amount_discount", - "applies_to_price_ids": ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - "percentage_discount": 0.15, - "trial_amount_discount": "trial_amount_discount", - "usage_discount": 0, - }, + "replaces_price_id": "replaces_price_id", + "discounts": [ + { + "discount_type": "percentage", + "amount_discount": "amount_discount", + "percentage_discount": 0.15, + "usage_discount": 0, + } + ], + "external_price_id": "external_price_id", "fixed_price_quantity": 2, "maximum_amount": "1.23", "minimum_amount": "1.23", - }, + "price": { + "cadence": "annual", + "item_id": "item_id", + "model_type": "unit", + "name": "Annual fee", + "unit_config": {"unit_amount": "unit_amount"}, + "billable_metric_id": "billable_metric_id", + "billed_in_advance": True, + "billing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "conversion_rate": 0, + "currency": "currency", + "external_price_id": "external_price_id", + "fixed_price_quantity": 0, + "invoice_grouping_key": "invoice_grouping_key", + "invoicing_cycle_configuration": { + "duration": 0, + "duration_unit": "day", + }, + "metadata": {"foo": "string"}, + "reference_id": "reference_id", + }, + "price_id": "h74gfhdjvn7ujokd", + } ], + trial_duration_days=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) @parametrize async def test_raw_response_schedule_plan_change(self, async_client: AsyncOrb) -> None: @@ -2073,7 +1958,7 @@ async def test_raw_response_schedule_plan_change(self, async_client: AsyncOrb) - assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_schedule_plan_change(self, async_client: AsyncOrb) -> None: @@ -2085,7 +1970,7 @@ async def test_streaming_response_schedule_plan_change(self, async_client: Async assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionSchedulePlanChangeResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2102,7 +1987,7 @@ async def test_method_trigger_phase(self, async_client: AsyncOrb) -> None: subscription = await async_client.subscriptions.trigger_phase( subscription_id="subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize async def test_method_trigger_phase_with_all_params(self, async_client: AsyncOrb) -> None: @@ -2110,7 +1995,7 @@ async def test_method_trigger_phase_with_all_params(self, async_client: AsyncOrb subscription_id="subscription_id", effective_date=parse_date("2019-12-27"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize async def test_raw_response_trigger_phase(self, async_client: AsyncOrb) -> None: @@ -2121,7 +2006,7 @@ async def test_raw_response_trigger_phase(self, async_client: AsyncOrb) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_trigger_phase(self, async_client: AsyncOrb) -> None: @@ -2132,7 +2017,7 @@ async def test_streaming_response_trigger_phase(self, async_client: AsyncOrb) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionTriggerPhaseResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2148,7 +2033,7 @@ async def test_method_unschedule_cancellation(self, async_client: AsyncOrb) -> N subscription = await async_client.subscriptions.unschedule_cancellation( "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_cancellation(self, async_client: AsyncOrb) -> None: @@ -2159,7 +2044,7 @@ async def test_raw_response_unschedule_cancellation(self, async_client: AsyncOrb assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_cancellation(self, async_client: AsyncOrb) -> None: @@ -2170,7 +2055,7 @@ async def test_streaming_response_unschedule_cancellation(self, async_client: As assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleCancellationResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2187,7 +2072,7 @@ async def test_method_unschedule_fixed_fee_quantity_updates(self, async_client: subscription_id="subscription_id", price_id="price_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_fixed_fee_quantity_updates(self, async_client: AsyncOrb) -> None: @@ -2199,7 +2084,7 @@ async def test_raw_response_unschedule_fixed_fee_quantity_updates(self, async_cl assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, async_client: AsyncOrb) -> None: @@ -2211,7 +2096,7 @@ async def test_streaming_response_unschedule_fixed_fee_quantity_updates(self, as assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnscheduleFixedFeeQuantityUpdatesResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2228,7 +2113,7 @@ async def test_method_unschedule_pending_plan_changes(self, async_client: AsyncO subscription = await async_client.subscriptions.unschedule_pending_plan_changes( "subscription_id", ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) @parametrize async def test_raw_response_unschedule_pending_plan_changes(self, async_client: AsyncOrb) -> None: @@ -2239,7 +2124,7 @@ async def test_raw_response_unschedule_pending_plan_changes(self, async_client: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_unschedule_pending_plan_changes(self, async_client: AsyncOrb) -> None: @@ -2250,7 +2135,7 @@ async def test_streaming_response_unschedule_pending_plan_changes(self, async_cl assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUnschedulePendingPlanChangesResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2268,7 +2153,7 @@ async def test_method_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> price_id="price_id", quantity=0, ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) @parametrize async def test_method_update_fixed_fee_quantity_with_all_params(self, async_client: AsyncOrb) -> None: @@ -2279,7 +2164,7 @@ async def test_method_update_fixed_fee_quantity_with_all_params(self, async_clie change_option="immediate", effective_date=parse_date("2022-12-21"), ) - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) @parametrize async def test_raw_response_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> None: @@ -2292,7 +2177,7 @@ async def test_raw_response_update_fixed_fee_quantity(self, async_client: AsyncO assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) @parametrize async def test_streaming_response_update_fixed_fee_quantity(self, async_client: AsyncOrb) -> None: @@ -2305,7 +2190,7 @@ async def test_streaming_response_update_fixed_fee_quantity(self, async_client: assert response.http_request.headers.get("X-Stainless-Lang") == "python" subscription = await response.parse() - assert_matches_type(Subscription, subscription, path=["response"]) + assert_matches_type(SubscriptionUpdateFixedFeeQuantityResponse, subscription, path=["response"]) assert cast(Any, response.is_closed) is True @@ -2317,3 +2202,54 @@ async def test_path_params_update_fixed_fee_quantity(self, async_client: AsyncOr price_id="price_id", quantity=0, ) + + @parametrize + async def test_method_update_trial(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + @parametrize + async def test_method_update_trial_with_all_params(self, async_client: AsyncOrb) -> None: + subscription = await async_client.subscriptions.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + shift=True, + ) + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + @parametrize + async def test_raw_response_update_trial(self, async_client: AsyncOrb) -> None: + response = await async_client.subscriptions.with_raw_response.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + subscription = response.parse() + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + @parametrize + async def test_streaming_response_update_trial(self, async_client: AsyncOrb) -> None: + async with async_client.subscriptions.with_streaming_response.update_trial( + subscription_id="subscription_id", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + subscription = await response.parse() + assert_matches_type(SubscriptionUpdateTrialResponse, subscription, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update_trial(self, async_client: AsyncOrb) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `subscription_id` but received ''"): + await async_client.subscriptions.with_raw_response.update_trial( + subscription_id="", + trial_end_date=parse_datetime("2017-07-21T17:32:28Z"), + ) diff --git a/tests/conftest.py b/tests/conftest.py index a718a9e3..89aeb3fe 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,11 @@ from __future__ import annotations import os -import asyncio import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator import pytest +from pytest_asyncio import is_async_test from orb import Orb, AsyncOrb @@ -17,11 +17,13 @@ logging.getLogger("orb").setLevel(logging.DEBUG) -@pytest.fixture(scope="session") -def event_loop() -> Iterator[asyncio.AbstractEventLoop]: - loop = asyncio.new_event_loop() - yield loop - loop.close() +# automatically add `pytest.mark.asyncio()` to all of our async tests +# so we don't have to add that boilerplate everywhere +def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: + pytest_asyncio_tests = (item for item in items if is_async_test(item)) + session_scope_marker = pytest.mark.asyncio(loop_scope="session") + for async_test in pytest_asyncio_tests: + async_test.add_marker(session_scope_marker, append=False) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/test_client.py b/tests/test_client.py index 9d34c15d..6155e0e0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,12 +4,16 @@ import gc import os +import sys import json import asyncio import inspect +import subprocess import tracemalloc from typing import Any, Union, cast +from textwrap import dedent from unittest import mock +from typing_extensions import Literal import httpx import pytest @@ -708,6 +712,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -752,7 +757,14 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retries_taken(self, client: Orb, failures_before_success: int, respx_mock: MockRouter) -> None: + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) + def test_retries_taken( + self, + client: Orb, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, + ) -> None: client = client.with_options(max_retries=4) nb_retries = 0 @@ -761,14 +773,65 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: nonlocal nb_retries if nb_retries < failures_before_success: nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") return httpx.Response(500) return httpx.Response(200) respx_mock.post("/customers").mock(side_effect=retry_handler) - response = client.customers.with_raw_response.create(email="email", name="x") + response = client.customers.with_raw_response.create(email="dev@stainlessapi.com", name="x") assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_omit_retry_count_header(self, client: Orb, failures_before_success: int, respx_mock: MockRouter) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/customers").mock(side_effect=retry_handler) + + response = client.customers.with_raw_response.create( + email="dev@stainlessapi.com", name="x", extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_overwrite_retry_count_header( + self, client: Orb, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/customers").mock(side_effect=retry_handler) + + response = client.customers.with_raw_response.create( + email="dev@stainlessapi.com", name="x", extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -789,8 +852,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/customers").mock(side_effect=retry_handler) - with client.customers.with_streaming_response.create(email="email", name="x") as response: + with client.customers.with_streaming_response.create(email="dev@stainlessapi.com", name="x") as response: assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success class TestAsyncOrb: @@ -1469,6 +1533,7 @@ class Model(BaseModel): [3, "", 0.5], [2, "", 0.5 * 2.0], [1, "", 0.5 * 4.0], + [-1100, "", 8], # test large number potentially overflowing ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -1515,8 +1580,13 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @pytest.mark.asyncio + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( - self, async_client: AsyncOrb, failures_before_success: int, respx_mock: MockRouter + self, + async_client: AsyncOrb, + failures_before_success: int, + failure_mode: Literal["status", "exception"], + respx_mock: MockRouter, ) -> None: client = async_client.with_options(max_retries=4) @@ -1526,14 +1596,69 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: nonlocal nb_retries if nb_retries < failures_before_success: nb_retries += 1 + if failure_mode == "exception": + raise RuntimeError("oops") return httpx.Response(500) return httpx.Response(200) respx_mock.post("/customers").mock(side_effect=retry_handler) - response = await client.customers.with_raw_response.create(email="email", name="x") + response = await client.customers.with_raw_response.create(email="dev@stainlessapi.com", name="x") assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_omit_retry_count_header( + self, async_client: AsyncOrb, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/customers").mock(side_effect=retry_handler) + + response = await client.customers.with_raw_response.create( + email="dev@stainlessapi.com", name="x", extra_headers={"x-stainless-retry-count": Omit()} + ) + + assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 + + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) + @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + @pytest.mark.asyncio + async def test_overwrite_retry_count_header( + self, async_client: AsyncOrb, failures_before_success: int, respx_mock: MockRouter + ) -> None: + client = async_client.with_options(max_retries=4) + + nb_retries = 0 + + def retry_handler(_request: httpx.Request) -> httpx.Response: + nonlocal nb_retries + if nb_retries < failures_before_success: + nb_retries += 1 + return httpx.Response(500) + return httpx.Response(200) + + respx_mock.post("/customers").mock(side_effect=retry_handler) + + response = await client.customers.with_raw_response.create( + email="dev@stainlessapi.com", name="x", extra_headers={"x-stainless-retry-count": "42"} + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("orb._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1555,5 +1680,41 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/customers").mock(side_effect=retry_handler) - async with client.customers.with_streaming_response.create(email="email", name="x") as response: + async with client.customers.with_streaming_response.create(email="dev@stainlessapi.com", name="x") as response: assert response.retries_taken == failures_before_success + assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + + def test_get_platform(self) -> None: + # A previous implementation of asyncify could leave threads unterminated when + # used with nest_asyncio. + # + # Since nest_asyncio.apply() is global and cannot be un-applied, this + # test is run in a separate process to avoid affecting other tests. + test_code = dedent(""" + import asyncio + import nest_asyncio + import threading + + from orb._utils import asyncify + from orb._base_client import get_platform + + async def test_main() -> None: + result = await asyncify(get_platform)() + print(result) + for thread in threading.enumerate(): + print(thread.name) + + nest_asyncio.apply() + asyncio.run(test_main()) + """) + with subprocess.Popen( + [sys.executable, "-c", test_code], + text=True, + ) as process: + try: + process.wait(2) + if process.returncode: + raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") + except subprocess.TimeoutExpired as e: + process.kill() + raise AssertionError("calling get_platform using asyncify resulted in a hung process") from e diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index 3ec62d81..3cabbaf5 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -32,6 +32,31 @@ def test_response_parse_mismatched_basemodel(client: Orb) -> None: response.parse(to=PydanticModel) +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: Orb, content: str, expected: bool) -> None: + response = LegacyAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + def test_response_parse_custom_stream(client: Orb) -> None: response = LegacyAPIResponse( raw=httpx.Response(200, content=b"foo"), diff --git a/tests/test_models.py b/tests/test_models.py index 97fe0e3d..6c5a7624 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -245,7 +245,7 @@ class Model(BaseModel): assert m.foo is True m = Model.construct(foo="CARD_HOLDER") - assert m.foo is "CARD_HOLDER" + assert m.foo == "CARD_HOLDER" m = Model.construct(foo={"bar": False}) assert isinstance(m.foo, Submodel1) @@ -520,19 +520,15 @@ class Model(BaseModel): assert m3.to_dict(exclude_none=True) == {} assert m3.to_dict(exclude_defaults=True) == {} - if PYDANTIC_V2: + class Model2(BaseModel): + created_at: datetime - class Model2(BaseModel): - created_at: datetime - - time_str = "2024-03-21T11:39:01.275859" - m4 = Model2.construct(created_at=time_str) - assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} - assert m4.to_dict(mode="json") == {"created_at": time_str} - else: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.to_dict(mode="json") + time_str = "2024-03-21T11:39:01.275859" + m4 = Model2.construct(created_at=time_str) + assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} + assert m4.to_dict(mode="json") == {"created_at": time_str} + if not PYDANTIC_V2: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -558,9 +554,6 @@ class Model(BaseModel): assert m3.model_dump(exclude_none=True) == {} if not PYDANTIC_V2: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.model_dump(mode="json") - with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -568,6 +561,14 @@ class Model(BaseModel): m.model_dump(warnings=False) +def test_compat_method_no_error_for_warnings() -> None: + class Model(BaseModel): + foo: Optional[str] + + m = Model(foo="hello") + assert isinstance(model_dump(m, warnings=False), dict) + + def test_to_json() -> None: class Model(BaseModel): foo: Optional[str] = Field(alias="FOO", default=None) diff --git a/tests/test_response.py b/tests/test_response.py index 52ea7467..db04a272 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -190,6 +190,56 @@ async def test_async_response_parse_annotated_type(async_client: AsyncOrb) -> No assert obj.bar == 2 +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +def test_response_parse_bool(client: Orb, content: str, expected: bool) -> None: + response = APIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = response.parse(to=bool) + assert result is expected + + +@pytest.mark.parametrize( + "content, expected", + [ + ("false", False), + ("true", True), + ("False", False), + ("True", True), + ("TrUe", True), + ("FalSe", False), + ], +) +async def test_async_response_parse_bool(client: AsyncOrb, content: str, expected: bool) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=content), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + result = await response.parse(to=bool) + assert result is expected + + class OtherModel(BaseModel): a: str diff --git a/tests/test_transform.py b/tests/test_transform.py index 23bc9faf..b0cb5089 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -177,17 +177,32 @@ class DateDict(TypedDict, total=False): foo: Annotated[date, PropertyInfo(format="iso8601")] +class DatetimeModel(BaseModel): + foo: datetime + + +class DateModel(BaseModel): + foo: Optional[date] + + @parametrize @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") + tz = "Z" if PYDANTIC_V2 else "+00:00" assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] dt = dt.replace(tzinfo=None) assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] + assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { + "foo": "2023-02-23" + } # type: ignore[comparison-overlap] @parametrize